From fc87645d4244886116cef40adb81af56c0bbb5cc Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 12 Nov 2014 03:02:10 +0300 Subject: [PATCH 01/34] svn: Refactored AnnotateClient and implementations - pass necessary peg revision as part of SvnTarget instance (instead of separate method argument) --- .../idea/svn/annotate/AnnotateClient.java | 1 - .../idea/svn/annotate/CmdAnnotateClient.java | 3 +-- .../idea/svn/annotate/SvnAnnotationProvider.java | 15 +++++++++------ .../idea/svn/annotate/SvnKitAnnotateClient.java | 9 ++++----- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/AnnotateClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/AnnotateClient.java index 90be057af431..3d4ea2a29346 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/AnnotateClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/AnnotateClient.java @@ -16,7 +16,6 @@ public interface AnnotateClient extends SvnClient { void annotate(@NotNull SvnTarget target, @NotNull SVNRevision startRevision, @NotNull SVNRevision endRevision, - @Nullable SVNRevision pegRevision, boolean includeMergedRevisions, @Nullable DiffOptions diffOptions, @Nullable AnnotationConsumer handler) throws VcsException; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/CmdAnnotateClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/CmdAnnotateClient.java index b48f14a41779..346905550d1d 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/CmdAnnotateClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/CmdAnnotateClient.java @@ -29,12 +29,11 @@ public class CmdAnnotateClient extends BaseSvnClient implements AnnotateClient { public void annotate(@NotNull SvnTarget target, @NotNull SVNRevision startRevision, @NotNull SVNRevision endRevision, - @Nullable SVNRevision pegRevision, boolean includeMergedRevisions, @Nullable DiffOptions diffOptions, @Nullable final AnnotationConsumer handler) throws VcsException { List parameters = new ArrayList(); - CommandUtil.put(parameters, target.getPathOrUrlString(), pegRevision); + CommandUtil.put(parameters, target); parameters.add("--revision"); parameters.add(startRevision + ":" + endRevision); CommandUtil.put(parameters, includeMergedRevisions, "--use-merge-history"); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java index e40569d720de..cdc8f42774f3 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java @@ -49,7 +49,10 @@ import org.tmatesoft.svn.core.wc2.SvnTarget; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; -import java.util.*; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAnnotationProvider { private static final Object MERGED_KEY = new Object(); @@ -135,9 +138,8 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn // TODO: only 2 elements will be in rp and for loop will be executed only once - probably rewrite with Pair AnnotateClient annotateClient = myVcs.getFactory(ioFile).createAnnotateClient(); for (int i = 0; i < rp.size() - 1; i++) { - annotateClient.annotate(SvnTarget.fromFile(ioFile), rp.get(i + 1), rp.get(i), ((SvnFileRevision)revision).getPegRevision(), - calculateMergeinfo, - getLogClientOptions(myVcs), annotateHandler); + annotateClient.annotate(SvnTarget.fromFile(ioFile, ((SvnFileRevision)revision).getPegRevision()), rp.get(i + 1), rp.get(i), + calculateMergeinfo, getLogClientOptions(myVcs), annotateHandler); } if (rp.get(1).getNumber() > 0) { @@ -254,8 +256,9 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn final boolean calculateMergeinfo = SvnConfiguration.getInstance(myVcs.getProject()).isShowMergeSourcesInAnnotate() && SvnUtil.checkRepositoryVersion15(myVcs, wasUrl.toString()); AnnotateClient client = myVcs.getFactory().createAnnotateClient(); - client.annotate(SvnTarget.fromURL(wasUrl), SVNRevision.create(1), svnRevision, svnRevision, calculateMergeinfo, - getLogClientOptions(myVcs), annotateHandler); + client + .annotate(SvnTarget.fromURL(wasUrl, svnRevision), SVNRevision.create(1), svnRevision, calculateMergeinfo, getLogClientOptions(myVcs), + annotateHandler); return result; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnKitAnnotateClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnKitAnnotateClient.java index c2423de0b70d..09420722a3fd 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnKitAnnotateClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnKitAnnotateClient.java @@ -24,7 +24,6 @@ public class SvnKitAnnotateClient extends BaseSvnClient implements AnnotateClien public void annotate(@NotNull SvnTarget target, @NotNull SVNRevision startRevision, @NotNull SVNRevision endRevision, - @Nullable SVNRevision pegRevision, boolean includeMergedRevisions, @Nullable DiffOptions diffOptions, @Nullable AnnotationConsumer handler) throws VcsException { @@ -34,13 +33,13 @@ public class SvnKitAnnotateClient extends BaseSvnClient implements AnnotateClien client.setDiffOptions(toDiffOptions(diffOptions)); if (target.isFile()) { client - .doAnnotate(target.getFile(), pegRevision, startRevision, endRevision, true, includeMergedRevisions, toAnnotateHandler(handler), - null); + .doAnnotate(target.getFile(), target.getPegRevision(), startRevision, endRevision, true, includeMergedRevisions, + toAnnotateHandler(handler), null); } else { client - .doAnnotate(target.getURL(), pegRevision, startRevision, endRevision, true, includeMergedRevisions, toAnnotateHandler(handler), - null); + .doAnnotate(target.getURL(), target.getPegRevision(), startRevision, endRevision, true, includeMergedRevisions, + toAnnotateHandler(handler), null); } } catch (SVNException e) { From 6ecda524bf32c3355cd05da79bc7e15fe334ade1 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 12 Nov 2014 13:59:01 +0300 Subject: [PATCH 02/34] IDEA-118826 Do not use peg revision for "svn annotate" on file target as file could be moved/renamed locally in working copy (and so this new not yet committed local path is not appropriate to be used with peg revision) --- .../jetbrains/idea/svn/annotate/SvnAnnotationProvider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java index cdc8f42774f3..960eb234042d 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/annotate/SvnAnnotationProvider.java @@ -138,8 +138,8 @@ public class SvnAnnotationProvider implements AnnotationProvider, VcsCacheableAn // TODO: only 2 elements will be in rp and for loop will be executed only once - probably rewrite with Pair AnnotateClient annotateClient = myVcs.getFactory(ioFile).createAnnotateClient(); for (int i = 0; i < rp.size() - 1; i++) { - annotateClient.annotate(SvnTarget.fromFile(ioFile, ((SvnFileRevision)revision).getPegRevision()), rp.get(i + 1), rp.get(i), - calculateMergeinfo, getLogClientOptions(myVcs), annotateHandler); + annotateClient.annotate(SvnTarget.fromFile(ioFile), rp.get(i + 1), rp.get(i), calculateMergeinfo, getLogClientOptions(myVcs), + annotateHandler); } if (rp.get(1).getNumber() > 0) { From 068f42ca1030d2e6bc703b3518f3da8b6e60aca3 Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 12 Nov 2014 15:58:00 +0300 Subject: [PATCH 03/34] svn: Fixed setting correct limit for "svn log" command - use configured history limit increased by 1 (to be able to check if there is more history to load) --- .../idea/svn/history/SvnHistoryProvider.java | 14 +++++++++----- .../idea/svn/history/SvnKitHistoryClient.java | 1 - 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java index 2ff19fcc56e6..3b25288b70b4 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java @@ -42,7 +42,9 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.*; import org.jetbrains.idea.svn.commandLine.SvnBindException; import org.jetbrains.idea.svn.info.Info; -import org.tmatesoft.svn.core.*; +import org.tmatesoft.svn.core.SVNCancelException; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; import org.tmatesoft.svn.core.internal.wc.SVNErrorManager; import org.tmatesoft.svn.core.wc.SVNRevision; @@ -171,8 +173,10 @@ public class SvnHistoryProvider @Override public void reportAppendableHistory(FilePath path, final VcsAppendableHistorySessionPartner partner) throws VcsException { - // we need + 1 rows to be reported to further detect that number of rows exceeded the limit - reportAppendableHistory(path, partner, null, null, VcsConfiguration.getInstance(myVcs.getProject()).MAXIMUM_HISTORY_ROWS + 1, null, false); + // request MAXIMUM_HISTORY_ROWS + 1 log entries to be able to detect if there are more log entries than it is configured to show - + // see LimitHistoryCheck + reportAppendableHistory(path, partner, null, null, VcsConfiguration.getInstance(myVcs.getProject()).MAXIMUM_HISTORY_ROWS + 1, null, + false); } public void reportAppendableHistory(FilePath path, final VcsAppendableHistorySessionPartner partner, @@ -324,7 +328,7 @@ public class SvnHistoryProvider target, myFrom == null ? SVNRevision.HEAD : myFrom, myTo == null ? SVNRevision.create(1) : myTo, - false, true, myShowMergeSources && mySupport15, myLimit + 1, null, + false, true, myShowMergeSources && mySupport15, myLimit, null, new MyLogEntryHandler(myVcs, myUrl, pegRevision, relativeUrl, createConsumerAdapter(myConsumer), repoRootURL, myFile.getCharset())); @@ -404,7 +408,7 @@ public class SvnHistoryProvider myVcs.getFactory(target).createHistoryClient() .doLog(target, operationalFrom, myTo == null ? SVNRevision.create(1) : myTo, false, true, myShowMergeSources && mySupport15, - myLimit + 1, null, handler); + myLimit, null, handler); } catch (SVNCancelException e) { // diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnKitHistoryClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnKitHistoryClient.java index 0aca8300e420..341cd557f93a 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnKitHistoryClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnKitHistoryClient.java @@ -31,7 +31,6 @@ public class SvnKitHistoryClient extends BaseSvnClient implements HistoryClient @Nullable String[] revisionProperties, @Nullable LogEntryConsumer handler) throws VcsException { try { - // TODO: a bug noticed when testing: we should pass "limit + 1" to get "limit" rows SVNLogClient client = myVcs.getSvnKitManager().createLogClient(); if (target.isFile()) { From 1a233da96f385d54e4d4603b23113c7e29cd7dae Mon Sep 17 00:00:00 2001 From: Alexander Marchuk Date: Wed, 12 Nov 2014 17:06:22 +0300 Subject: [PATCH 04/34] handle more then one line (prevent possible future BaseOutputReader change) --- .../python/debugger/pydev/RemoteDebugger.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java index 9264b4f0f027..63d763a99733 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java @@ -622,9 +622,18 @@ public class RemoteDebugger implements ProcessDebugger { @Override protected void onTextAvailable(@NotNull String text) { myTextBuilder.append(text); - if (text.endsWith("\n")) { - processResponse(myTextBuilder.toString()); + if (text.contains("\n")) { + String[] lines = myTextBuilder.toString().split("\n"); myTextBuilder = new StringBuilder(); + + if (!text.endsWith("\n")) { + myTextBuilder.append(lines[lines.length - 1]); + lines = Arrays.copyOfRange(lines, 0, lines.length - 1); + } + + for (String line : lines) { + processResponse(line); + } } } } From 2984693c35bbad5ce63e2028df984677f1f0532f Mon Sep 17 00:00:00 2001 From: Alexander Marchuk Date: Wed, 12 Nov 2014 17:11:32 +0300 Subject: [PATCH 05/34] add "\n" to processed response --- .../com/jetbrains/python/debugger/pydev/RemoteDebugger.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java index 63d763a99733..2fd0374ae545 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java @@ -632,7 +632,7 @@ public class RemoteDebugger implements ProcessDebugger { } for (String line : lines) { - processResponse(line); + processResponse(line + "\n"); } } } From 90e592e06885e11737423edfe35b475f3e788234 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Wed, 12 Nov 2014 17:20:51 +0300 Subject: [PATCH 06/34] [vcs-log] do not show color stripe in details in single-root projects IDEA-119107 --- .../impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java index 2079593706f3..0c8cdb4d9fb2 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java @@ -190,7 +190,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener { } private void updateDetailsBorder(@Nullable VcsFullCommitDetails data) { - if (data == null) { + if (data == null || !myColorManager.isMultipleRoots()) { myMainContentPanel.setBorder(BorderFactory.createEmptyBorder()); } else { From b4ac37aeabb9a0936588c65e7d422d9947dad038 Mon Sep 17 00:00:00 2001 From: Julia Beliaeva Date: Wed, 12 Nov 2014 17:23:24 +0300 Subject: [PATCH 07/34] [vcs-log] move root name to the end of the line IDEA-119107 --- .../impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java index 0c8cdb4d9fb2..abc2348e32d7 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/frame/DetailsPanel.java @@ -244,8 +244,8 @@ class DetailsPanel extends JPanel implements ListSelectionListener { myMainText = null; } else { - String header = (myMultiRoot ? "[" + commit.getRoot().getName() + "] " : "") + - commit.getId().toShortString() + " " + getAuthorText(commit); + String header = commit.getId().toShortString() + " " + getAuthorText(commit) + + (myMultiRoot ? " [" + commit.getRoot().getName() + "]" : ""); String body = getMessageText(commit); myMainText = header + "
" + body; } From 892f511589454457c72489860c5a23079fe89cf6 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 12 Nov 2014 15:59:53 +0100 Subject: [PATCH 08/34] IDEA-130959 (indicator passing + test) --- .../application/ex/ApplicationUtil.java | 31 ++++++++++------- .../openapi/fileEditor/impl/LoadTextUtil.java | 2 +- .../java/decompiler/IdeaDecompiler.java | 15 +++++++++ .../java/decompiler/IdeaDecompilerTest.java | 33 +++++++++++++++++++ 4 files changed, 69 insertions(+), 12 deletions(-) diff --git a/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationUtil.java b/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationUtil.java index 94061b31acee..a864652c503b 100644 --- a/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationUtil.java +++ b/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationUtil.java @@ -17,13 +17,17 @@ package com.intellij.openapi.application.ex; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Ref; import com.intellij.util.ExceptionUtil; import org.jetbrains.annotations.NotNull; -import java.util.concurrent.*; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; public class ApplicationUtil { // throws exception if can't grab read action right now @@ -50,25 +54,30 @@ public class ApplicationUtil { * Allows to interrupt a process which does not performs checkCancelled() calls by itself. * Note that the process may continue to run in background indefinitely - so avoid using this method unless absolutely needed. */ - public static T runWithCheckCanceled(@NotNull final Callable callable) throws Exception { + public static T runWithCheckCanceled(@NotNull final Callable callable, @NotNull final ProgressIndicator indicator) throws Exception { final Ref error = Ref.create(); Future future = ApplicationManager.getApplication().executeOnPooledThread(new Callable() { @Override public T call() throws Exception { - try { - return callable.call(); - } - catch (Throwable t) { - error.set(t); - return null; - } - }; + return ProgressManager.getInstance().runProcess(new Computable() { + @Override + public T compute() { + try { + return callable.call(); + } + catch (Throwable t) { + error.set(t); + return null; + } + } + }, indicator); + } }); while (true) { try { - ProgressManager.checkCanceled(); + indicator.checkCanceled(); } catch (ProcessCanceledException e) { future.cancel(true); diff --git a/platform/core-impl/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java b/platform/core-impl/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java index bf4c421c38ea..1d30e7e7e5d1 100644 --- a/platform/core-impl/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java +++ b/platform/core-impl/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java @@ -389,7 +389,7 @@ public final class LoadTextUtil { public CharSequence call() { return decompiler.decompile(file); } - })); + }, indicator)); } catch (Throwable t) { error.set(t); diff --git a/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.java b/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.java index b67f88b8b1ed..098cc7c6667a 100644 --- a/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.java +++ b/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.java @@ -27,6 +27,8 @@ import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.fileEditor.*; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.DefaultProjectFactory; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; @@ -47,6 +49,7 @@ import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; import org.jetbrains.java.decompiler.main.decompiler.BaseDecompiler; import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider; import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; @@ -74,6 +77,7 @@ public class IdeaDecompiler extends ClassFileDecompilers.Light { private final IFernflowerLogger myLogger = new IdeaLogger(); private final Map myOptions = new HashMap(); private boolean myLegalNoticeAccepted; + private volatile ProgressIndicator myProgress; public IdeaDecompiler() { myOptions.put(IFernflowerPreferences.HIDE_DEFAULT_CONSTRUCTOR, "0"); @@ -140,6 +144,8 @@ public class IdeaDecompiler extends ClassFileDecompilers.Light { return ClsFileImpl.decompile(file); } + myProgress = ProgressManager.getInstance().getProgressIndicator(); + try { Map files = ContainerUtil.newLinkedHashMap(); files.put(file.getPath(), file); @@ -193,6 +199,15 @@ public class IdeaDecompiler extends ClassFileDecompilers.Light { throw new CannotDecompileException(e); } } + finally { + myProgress = null; + } + } + + @TestOnly + @Nullable + public ProgressIndicator getProgress() { + return myProgress; } private static class MyBytecodeProvider implements IBytecodeProvider { diff --git a/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java b/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java index 81df4dd82859..ac7d27057348 100644 --- a/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java +++ b/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java @@ -18,8 +18,12 @@ package org.jetbrains.java.decompiler; import com.intellij.codeInsight.daemon.impl.IdentifierHighlighterPassFactory; import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction; import com.intellij.debugger.PositionManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.PluginPathManager; +import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.StdFileTypes; +import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.registry.Registry; @@ -28,9 +32,11 @@ import com.intellij.openapi.vfs.*; import com.intellij.pom.Navigatable; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.psi.compiled.ClassFileDecompilers; import com.intellij.psi.impl.compiled.ClsFileImpl; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; +import com.intellij.util.Alarm; import com.intellij.util.ThrowableRunnable; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.io.URLUtil; @@ -169,4 +175,31 @@ public class IdeaDecompilerTest extends LightCodeInsightFixtureTestCase { } }).cpuBound().assertTiming(); } + + public void testCancellation() { + VirtualFile file = getTestFile(PlatformTestUtil.getRtJarPath() + "!/javax/swing/JTable.class"); + + final IdeaDecompiler decompiler = (IdeaDecompiler)ClassFileDecompilers.find(file); + assertNotNull(decompiler); + + final Alarm alarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, getProject()); + alarm.addRequest(new Runnable() { + @Override + public void run() { + ProgressIndicator progress = decompiler.getProgress(); + if (progress != null) { + progress.cancel(); + } + else { + alarm.addRequest(this, 200, ModalityState.any()); + } + } + }, 750, ModalityState.any()); + + try { + FileDocumentManager.getInstance().getDocument(file); + fail("should have been cancelled"); + } + catch (ProcessCanceledException ignored) { } + } } From a25b91f6f77b92957efd58386b976fed09c6f8c5 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 12 Nov 2014 16:02:16 +0100 Subject: [PATCH 09/34] IDEA-130959 (do not start the progress when headless) --- .../src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/core-impl/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java b/platform/core-impl/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java index 1d30e7e7e5d1..2792ae0baf97 100644 --- a/platform/core-impl/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java +++ b/platform/core-impl/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java @@ -376,7 +376,7 @@ public final class LoadTextUtil { CharSequence text; Application app = ApplicationManager.getApplication(); - if (app != null && app.isDispatchThread() && !app.isWriteAccessAllowed()) { + if (app != null && app.isDispatchThread() && !app.isHeadlessEnvironment() && !app.isWriteAccessAllowed()) { final Ref result = Ref.create(ArrayUtil.EMPTY_CHAR_SEQUENCE); final Ref error = Ref.create(); ProgressManager.getInstance().run(new Task.Modal(null, "Decompiling " + file.getName(), true) { From 9c943d08caa29f5e56b581b825ff39e693b09591 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 12 Nov 2014 16:11:46 +0100 Subject: [PATCH 10/34] IDEA-130959 (do not start the progress when really headless) --- .../src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/core-impl/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java b/platform/core-impl/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java index 2792ae0baf97..6f1d24e4a8c3 100644 --- a/platform/core-impl/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java +++ b/platform/core-impl/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java @@ -43,6 +43,7 @@ import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.awt.*; import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; @@ -376,7 +377,7 @@ public final class LoadTextUtil { CharSequence text; Application app = ApplicationManager.getApplication(); - if (app != null && app.isDispatchThread() && !app.isHeadlessEnvironment() && !app.isWriteAccessAllowed()) { + if (app != null && app.isDispatchThread() && !app.isWriteAccessAllowed() && !GraphicsEnvironment.isHeadless()) { final Ref result = Ref.create(ArrayUtil.EMPTY_CHAR_SEQUENCE); final Ref error = Ref.create(); ProgressManager.getInstance().run(new Task.Modal(null, "Decompiling " + file.getName(), true) { From b8f6164dced1d9b4e4464f3962201bc2818061d5 Mon Sep 17 00:00:00 2001 From: irengrig Date: Wed, 12 Nov 2014 16:14:11 +0100 Subject: [PATCH 11/34] v8 profiling, allow to filer call tree by total % --- .../ui/components/SliderSelectorAction.java | 196 ++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 platform/platform-impl/src/com/intellij/ui/components/SliderSelectorAction.java diff --git a/platform/platform-impl/src/com/intellij/ui/components/SliderSelectorAction.java b/platform/platform-impl/src/com/intellij/ui/components/SliderSelectorAction.java new file mode 100644 index 000000000000..39d81e6fb487 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/ui/components/SliderSelectorAction.java @@ -0,0 +1,196 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.ui.components; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.ui.popup.JBPopup; +import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.ui.awt.RelativePoint; +import com.intellij.util.Consumer; +import com.intellij.util.ui.SwingHelper; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.util.Dictionary; +import java.util.Enumeration; +import java.util.Hashtable; + +/** + * @author Irina.Chernushina on 11/12/2014. + */ +public class SliderSelectorAction extends DumbAwareAction { + @NotNull private final Configuration myConfiguration; + + public SliderSelectorAction(@Nullable String text, @Nullable String description, @Nullable Icon icon, + @NotNull Configuration configuration) { + super(text, description, icon); + myConfiguration = configuration; + } + + @Override + public void update(@NotNull AnActionEvent e) { + super.update(e); + final String tooltip = myConfiguration.getTooltip(); + if (tooltip != null) { + e.getPresentation().setText(getTemplatePresentation().getText() + " (" + tooltip + ")"); + e.getPresentation().setDescription(getTemplatePresentation().getDescription() + " (" + tooltip + ")"); + } + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + final JPanel result = new JPanel(new BorderLayout()); + final JLabel label = new JLabel(myConfiguration.getSelectText()); + label.setBorder(BorderFactory.createEmptyBorder(4, 4, 0, 0)); + JPanel wrapper = new JPanel(new BorderLayout()); + wrapper.add(label, BorderLayout.NORTH); + result.add(wrapper, BorderLayout.WEST); + + final JSlider slider = new JSlider(SwingConstants.HORIZONTAL, myConfiguration.getMin(), myConfiguration.getMax(), myConfiguration.getSelected()); + slider.setMinorTickSpacing(1); + slider.setPaintTicks(true); + slider.setPaintTrack(true); + slider.setSnapToTicks(true); + UIUtil.setSliderIsFilled(slider, true); + slider.setPaintLabels(true); + slider.setLabelTable(myConfiguration.getDictionary()); + result.add(slider, BorderLayout.CENTER); + final Runnable[] closeMe = new Runnable[1]; + if (myConfiguration.isShowOk()) { + final JButton done = new JButton("Done"); + result.add(SwingHelper.wrapWithoutStretch(done), BorderLayout.SOUTH); + done.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (closeMe[0] != null) closeMe[0].run(); + } + }); + } + + final JBPopup popup = JBPopupFactory.getInstance().createComponentPopupBuilder(result, slider).createPopup(); + final Runnable finalRunnable = new Runnable() { + @Override + public void run() { + int value = slider.getModel().getValue(); + myConfiguration.getResultConsumer().consume(value); + } + }; + closeMe[0] = new Runnable() { + @Override + public void run() { + finalRunnable.run(); + popup.closeOk(null); + } + }; + popup.setFinalRunnable(finalRunnable); + InputEvent inputEvent = e.getInputEvent(); + if (inputEvent instanceof MouseEvent) { + int width = result.getPreferredSize().width; + MouseEvent inputEvent1 = (MouseEvent)inputEvent; + Point point1 = new Point(inputEvent1.getX() - width / 2, inputEvent1.getY()); + RelativePoint point = new RelativePoint(inputEvent1.getComponent(), point1); + popup.show(point); + } else { + popup.showInBestPositionFor(e.getDataContext()); + } + } + + public static class Configuration { + @NotNull + private final String mySelectText; + @NotNull + private final Dictionary myDictionary; + private final int mySelected; + private final int myMin; + private final int myMax; + @NotNull + private final Consumer myResultConsumer; + private boolean showOk = false; + + public Configuration(int selected, @NotNull Dictionary dictionary, @NotNull String selectText, @NotNull Consumer consumer) { + mySelected = selected; + myDictionary = new Hashtable(); + mySelectText = selectText; + myResultConsumer = consumer; + + int min = 1; + int max = 0; + final Enumeration keys = dictionary.keys(); + while (keys.hasMoreElements()) { + final Integer key = (Integer)keys.nextElement(); + final String value = (String)dictionary.get(key); + myDictionary.put(key, markLabel(value)); + min = Math.min(min, key); + max = Math.max(max, key); + } + myMin = min; + myMax = max; + } + + private static JLabel markLabel(final String text) { + JLabel label = new JLabel(text); + label.setFont(UIUtil.getLabelFont()); + return label; + } + + @NotNull + public String getSelectText() { + return mySelectText; + } + + @NotNull + public Dictionary getDictionary() { + return myDictionary; + } + + @NotNull + public Consumer getResultConsumer() { + return myResultConsumer; + } + + public int getSelected() { + return mySelected; + } + + public int getMin() { + return myMin; + } + + public int getMax() { + return myMax; + } + + public boolean isShowOk() { + return showOk; + } + + public void setShowOk(boolean showOk) { + this.showOk = showOk; + } + + public String getTooltip() { + return null; + } + } +} From 61608d28386edea55a2db2f2d87489669d366aab Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 12 Nov 2014 18:43:49 +0300 Subject: [PATCH 12/34] IDEA-118950 Only set limit for "svn log" command if corresponding history limit is configured in settings --- .../org/jetbrains/idea/svn/history/SvnHistoryProvider.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java index 3b25288b70b4..c5bc11f485bd 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java @@ -175,8 +175,10 @@ public class SvnHistoryProvider public void reportAppendableHistory(FilePath path, final VcsAppendableHistorySessionPartner partner) throws VcsException { // request MAXIMUM_HISTORY_ROWS + 1 log entries to be able to detect if there are more log entries than it is configured to show - // see LimitHistoryCheck - reportAppendableHistory(path, partner, null, null, VcsConfiguration.getInstance(myVcs.getProject()).MAXIMUM_HISTORY_ROWS + 1, null, - false); + VcsConfiguration configuration = VcsConfiguration.getInstance(myVcs.getProject()); + int limit = configuration.LIMIT_HISTORY ? configuration.MAXIMUM_HISTORY_ROWS + 1 : 0; + + reportAppendableHistory(path, partner, null, null, limit, null, false); } public void reportAppendableHistory(FilePath path, final VcsAppendableHistorySessionPartner partner, From b8064547e4e60369f13d6ff60f2ff82c42feb8ca Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 12 Nov 2014 12:26:48 +0100 Subject: [PATCH 13/34] =?UTF-8?q?UpdateChecker=20=E2=80=94=20use=20platfor?= =?UTF-8?q?m=20timeout=20defaults=20(5=20sec=20connection=20timeout=20coul?= =?UTF-8?q?d=20be=20not=20enough=20even=20in=20normal=20case)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../openapi/updateSettings/impl/UpdateChecker.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java index 08ed9832de5c..f3a8f5677371 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java @@ -41,7 +41,10 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.StandardFileSystems; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.*; +import com.intellij.util.Function; +import com.intellij.util.HttpRequests; +import com.intellij.util.PlatformUtils; +import com.intellij.util.ThrowableConvertor; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.io.UrlConnectionUtil; import com.intellij.util.net.HttpConfigurable; @@ -471,8 +474,6 @@ public final class UpdateChecker { } return HttpRequests.request(updateUrl.startsWith("file:") ? updateUrl : updateUrl + '?' + prepareUpdateCheckArgs()) - .connectTimeout(5 * Time.SECOND) - .readTimeout(5 * Time.SECOND) .get(new ThrowableConvertor() { @Override public UpdatesInfo convert(URLConnection connection) throws Exception { From 1d20c54efc3ab182605bc21ca0476971d1703d10 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 12 Nov 2014 13:05:29 +0100 Subject: [PATCH 14/34] cleanup --- .../updateSettings/impl/PluginDownloader.java | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java index 4bc51f9b2e36..dadacc59bfea 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java @@ -176,11 +176,7 @@ public class PluginDownloader { if (file.getName().endsWith(".zip")) { final File outputDir = FileUtil.createTempDirectory("plugin", ""); try { - ZipUtil.extract(file, outputDir, new FilenameFilter() { - public boolean accept(final File dir, final String name) { - return true; - } - }); + ZipUtil.extract(file, outputDir, null); final File[] files = outputDir.listFiles(); if (files != null && files.length == 1) { descriptor = PluginManagerCore.loadDescriptor(files[0], PluginManagerCore.PLUGIN_XML); @@ -250,7 +246,11 @@ public class PluginDownloader { URLConnection connection = null; try { - connection = openConnection(myPluginUrl); + Pair result = HttpRequests.openConnection(myPluginUrl, false); + if (result.second != null) { + myPluginUrl = result.second; + } + connection = result.first; final InputStream is = (ApplicationManager.getApplication() != null) ? UrlConnectionUtil.getConnectionInputStream(connection, progressIndicator) @@ -290,14 +290,6 @@ public class PluginDownloader { } } - private URLConnection openConnection(@NotNull String url) throws IOException { - Pair result = HttpRequests.openConnection(url, false); - if (result.second != null) { - myPluginUrl = result.second; - } - return result.first; - } - @NotNull private String guessFileName(final URLConnection connection, final File file) throws IOException { String fileName = null; From 831ba120f6aac02cde3aed3b8835dd127c2d2227 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 12 Nov 2014 13:07:57 +0100 Subject: [PATCH 15/34] cleanup --- .../ide/customize/CustomizeFeaturedPluginsStepPanel.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/customize/CustomizeFeaturedPluginsStepPanel.java b/platform/platform-impl/src/com/intellij/ide/customize/CustomizeFeaturedPluginsStepPanel.java index 5800120dd4ce..fb813ea27b1c 100644 --- a/platform/platform-impl/src/com/intellij/ide/customize/CustomizeFeaturedPluginsStepPanel.java +++ b/platform/platform-impl/src/com/intellij/ide/customize/CustomizeFeaturedPluginsStepPanel.java @@ -46,7 +46,7 @@ import java.util.concurrent.atomic.AtomicBoolean; public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardStep { private static final int COLS = 3; - private static ScheduledExecutorService ourService = new ScheduledThreadPoolExecutor(4, ConcurrencyUtil.newNamedThreadFactory( + private static final ScheduledExecutorService ourService = new ScheduledThreadPoolExecutor(4, ConcurrencyUtil.newNamedThreadFactory( "FeaturedPlugins", true, Thread.NORM_PRIORITY)); public final AtomicBoolean myCanceled = new AtomicBoolean(false); @@ -119,7 +119,6 @@ public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardSt wrapperLayout.show(buttonWrapper, "button"); final ProgressIndicatorEx indicator = new AbstractProgressIndicatorExBase(true) { - @Override public void start() { myCanceled.set(false); @@ -264,5 +263,5 @@ public class CustomizeFeaturedPluginsStepPanel extends AbstractCustomizeWizardSt + " | " + "Plugins"; } - public static class OfflineException extends Exception {}; + public static class OfflineException extends Exception {} } From d924786ea3eda6630eec69c0bc79951b39567fe7 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 12 Nov 2014 13:35:12 +0100 Subject: [PATCH 16/34] cleanup, progress indicator nullability --- .../plugins/InstalledPluginsTableModel.java | 16 ++-- .../ide/plugins/PluginHostsConfigurable.java | 78 +++++++++++-------- .../ide/plugins/PluginManagerMain.java | 21 ++++- .../updateSettings/impl/PluginDownloader.java | 11 +-- .../impl/PluginUpdateInfoDialog.java | 20 +++-- .../updateSettings/impl/UpdateChecker.java | 14 ++-- 6 files changed, 96 insertions(+), 64 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/InstalledPluginsTableModel.java b/platform/platform-impl/src/com/intellij/ide/plugins/InstalledPluginsTableModel.java index 70384f3f2f2d..9021029be77f 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/InstalledPluginsTableModel.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/InstalledPluginsTableModel.java @@ -34,6 +34,7 @@ import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.hash.HashSet; import com.intellij.util.ui.ColumnInfo; +import gnu.trove.THashMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -145,30 +146,29 @@ public class InstalledPluginsTableModel extends PluginTableModel { updatePluginDependencies(); - final Runnable runnable = new Runnable() { + SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (!ApplicationManager.getApplication().isDisposed()) { ProgressManager.getInstance().run(new Task.Backgroundable(null, "Load custom plugin repositories data...") { @Override public void run(@NotNull ProgressIndicator indicator) { - updateRepositoryPlugins(); + updateRepositoryPlugins(indicator); } }); } } - }; - SwingUtilities.invokeLater(runnable); + }); } - public void updateRepositoryPlugins() { + private void updateRepositoryPlugins(@NotNull ProgressIndicator indicator) { myPlugin2host.clear(); - final List pluginHosts = UpdateSettings.getInstance().getPluginHosts(); + List pluginHosts = UpdateSettings.getInstance().getPluginHosts(); ContainerUtil.addIfNotNull(ApplicationInfoEx.getInstanceEx().getBuiltinPluginsUrl(), pluginHosts); for (String host : pluginHosts) { try { - final Map downloaded = new HashMap(); - UpdateChecker.checkPluginsHost(host, downloaded, false, null); + Map downloaded = new THashMap(); + UpdateChecker.checkPluginsHost(host, downloaded, false, indicator); for (PluginId pluginId : downloaded.keySet()) { myPlugin2host.put(pluginId.getIdString(), host); } diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java index 686e6f9db79e..5225149172f0 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginHostsConfigurable.java @@ -19,7 +19,9 @@ import com.intellij.ide.IdeBundle; import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.options.BaseConfigurable; import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; import com.intellij.openapi.ui.InputValidator; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.NonEmptyInputValidator; @@ -35,33 +37,37 @@ import com.intellij.ui.ToolbarDecorator; import com.intellij.ui.components.JBList; import com.intellij.util.ArrayUtil; import com.intellij.util.io.URLUtil; +import gnu.trove.THashMap; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.event.DocumentEvent; import java.awt.*; import java.awt.event.ActionEvent; import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; import java.util.List; public class PluginHostsConfigurable extends BaseConfigurable { private CustomPluginRepositoriesPanel myUpdatesSettingsPanel; + @Override public JComponent createComponent() { myUpdatesSettingsPanel = new CustomPluginRepositoriesPanel(); return myUpdatesSettingsPanel.myPanel; } + @Override public String getDisplayName() { return "Custom Plugin Repositories"; } + @Override public String getHelpTopic() { return null; } + @Override public void apply() throws ConfigurationException { UpdateSettings settings = UpdateSettings.getInstance(); @@ -69,27 +75,28 @@ public class PluginHostsConfigurable extends BaseConfigurable { settings.myPluginHosts.addAll(myUpdatesSettingsPanel.getPluginsHosts()); } + @Override public void reset() { myUpdatesSettingsPanel.setPluginHosts(UpdateSettings.getInstance().myPluginHosts); } + @Override public boolean isModified() { - if (myUpdatesSettingsPanel == null) return false; - UpdateSettings settings = UpdateSettings.getInstance(); - return !settings.myPluginHosts.equals(myUpdatesSettingsPanel.getPluginsHosts()); + if (myUpdatesSettingsPanel == null) { + return false; + } + //noinspection EqualsBetweenInconvertibleTypes + return !UpdateSettings.getInstance().myPluginHosts.equals(myUpdatesSettingsPanel.getPluginsHosts()); } + @Override public void disposeUIResources() { myUpdatesSettingsPanel = null; } - public Collection getPluginsHosts() { - return myUpdatesSettingsPanel.getPluginsHosts(); - } - public static class CustomPluginRepositoriesPanel { - private JBList myUrlsList; - private JPanel myPanel; + private final JBList myUrlsList; + private final JPanel myPanel; public CustomPluginRepositoriesPanel() { myUrlsList = new JBList(new DefaultListModel()); @@ -109,6 +116,7 @@ public class PluginHostsConfigurable extends BaseConfigurable { dlg.show(); String input = dlg.getInputString(); if (input != null) { + //noinspection unchecked ((DefaultListModel)myUrlsList.getModel()).addElement(correctRepositoryRule(input)); } } @@ -122,10 +130,12 @@ public class PluginHostsConfigurable extends BaseConfigurable { Messages.getQuestionIcon(), (String)myUrlsList.getSelectedValue(), new InputValidator() { + @Override public boolean checkInput(final String inputString) { return inputString.length() > 0; } + @Override public boolean canClose(final String inputString) { return checkInput(inputString); } @@ -133,6 +143,7 @@ public class PluginHostsConfigurable extends BaseConfigurable { dlg.show(); final String input = dlg.getInputString(); if (input != null) { + //noinspection unchecked ((DefaultListModel)myUrlsList.getModel()).set(myUrlsList.getSelectedIndex(), input); } } @@ -152,6 +163,7 @@ public class PluginHostsConfigurable extends BaseConfigurable { final DefaultListModel model = (DefaultListModel)myUrlsList.getModel(); model.clear(); for (String host : pluginHosts) { + //noinspection unchecked model.addElement(host); } } @@ -177,35 +189,39 @@ public class PluginHostsConfigurable extends BaseConfigurable { super(parentComponent, message, title, icon, initialValue, validator); } + @Override @NotNull protected Action[] createActions() { - final Action[] actions = super.createActions(); final AbstractAction checkNowAction = new AbstractAction("Check Now") { - public void actionPerformed(final ActionEvent e) { - final boolean[] result = new boolean[1]; - final Exception[] ex = new Exception[1]; - if (ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { + @Override + public void actionPerformed(@Nullable ActionEvent e) { + ProgressManager.getInstance().run(new Task.Modal(null, "Checking plugins repository...", true) { + boolean result; + Exception ex; + @Override - public void run() { + public void run(@NotNull ProgressIndicator indicator) { try { - result[0] = - UpdateChecker.checkPluginsHost(correctRepositoryRule(getTextField().getText()), new HashMap(), true, ProgressManager.getInstance().getProgressIndicator()); + result = UpdateChecker.checkPluginsHost(correctRepositoryRule(getTextField().getText()), new THashMap(), true, indicator); } catch (Exception e1) { - ex[0] = e1; + ex = e1; } } - }, "Checking plugins repository...", true, null, getPreferredFocusedComponent())) { - if (ex[0] != null) { - showErrorDialog(myField, "Connection failed: " + ex[0].getMessage()); + + @Override + public void onSuccess() { + if (ex != null) { + showErrorDialog(myField, "Connection failed: " + ex.getMessage()); + } + else if (result) { + showInfoMessage(myField, "Plugins repository was successfully checked", "Check Plugins Repository"); + } + else { + showErrorDialog(myField, "Plugin descriptions contain some errors. Please, check idea.log for details."); + } } - else if (result[0]) { - showInfoMessage(myField, "Plugins repository was successfully checked", "Check Plugins Repository"); - } - else { - showErrorDialog(myField, "Plugin descriptions contain some errors. Please, check idea.log for details."); - } - } + }); } }; myField.getDocument().addDocumentListener(new DocumentAdapter() { @@ -215,7 +231,7 @@ public class PluginHostsConfigurable extends BaseConfigurable { } }); checkNowAction.setEnabled(!StringUtil.isEmptyOrSpaces(myField.getText())); - return ArrayUtil.append(actions, checkNowAction); + return ArrayUtil.append(super.createActions(), checkNowAction); } } } diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java index ded719147d3b..f4d862109606 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.java @@ -54,6 +54,7 @@ import com.intellij.util.concurrency.SwingWorker; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.update.UiNotifyConnector; import com.intellij.xml.util.XmlStringUtil; +import gnu.trove.THashMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -213,6 +214,7 @@ public abstract class PluginManagerMain implements Disposable { protected abstract JScrollPane createTable(); + @Override public void dispose() { myDisposed = true; } @@ -227,6 +229,7 @@ public abstract class PluginManagerMain implements Disposable { public void reset() { UiNotifyConnector.doWhenFirstShown(getPluginTable(), new Runnable() { + @Override public void run() { requireShutdown = false; TableUtil.ensureSelectionExists(getPluginTable()); @@ -245,6 +248,7 @@ public abstract class PluginManagerMain implements Disposable { protected void installTableActions() { pluginTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + @Override public void valueChanged(ListSelectionEvent e) { refresh(); } @@ -306,6 +310,7 @@ public abstract class PluginManagerMain implements Disposable { List list = null; List errorMessages = new ArrayList(); + @Override public Object construct() { try { list = RepositoryHelper.loadPluginsFromRepository(null); @@ -325,8 +330,10 @@ public abstract class PluginManagerMain implements Disposable { } void processPluginHost(@NotNull String host, boolean builtIn) { - if (!acceptHost(host)) return; - final Map downloaded = new HashMap(); + if (!acceptHost(host)) { + return; + } + Map downloaded = new THashMap(); try { UpdateChecker.checkPluginsHost(host, downloaded, false, null); for (PluginDownloader downloader : downloaded.values()) { @@ -353,8 +360,10 @@ public abstract class PluginManagerMain implements Disposable { } } + @Override public void finished() { UIUtil.invokeLaterIfNeeded(new Runnable() { + @Override public void run() { setDownloadStatus(false); if (list != null) { @@ -383,7 +392,7 @@ public abstract class PluginManagerMain implements Disposable { } protected void loadAvailablePlugins() { - ArrayList list; + List list; try { // If we already have a file with downloaded plugins from the last time, // then read it, load into the list and start the updating process. @@ -546,6 +555,7 @@ public abstract class PluginManagerMain implements Disposable { } public static class MyHyperlinkListener implements HyperlinkListener { + @Override public void hyperlinkUpdate(HyperlinkEvent e) { if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { JEditorPane pane = (JEditorPane)e.getSource(); @@ -574,18 +584,22 @@ public abstract class PluginManagerMain implements Disposable { return getComponent().convertRowIndexToModel(viewIndex); } + @Override public int getSelectedIndex() { return myComponent.getSelectedRow(); } + @Override public Object[] getAllElements() { return myComponent.getElements(); } + @Override public String getElementText(Object element) { return ((IdeaPluginDescriptor)element).getName(); } + @Override public void selectElement(Object element, String selectedText) { for (int i = 0; i < myComponent.getRowCount(); i++) { if (myComponent.getObjectAt(i).getName().equals(((IdeaPluginDescriptor)element).getName())) { @@ -678,6 +692,7 @@ public abstract class PluginManagerMain implements Disposable { super("PLUGIN_FILTER", 5); } + @Override public void filter() { getPluginTable().putClientProperty(SpeedSearchSupply.SEARCH_QUERY_KEY, getFilter()); pluginsModel.filter(getFilter().toLowerCase()); diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java index dadacc59bfea..3f72c3881164 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java @@ -23,7 +23,6 @@ import com.intellij.openapi.application.PathManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.util.ProgressIndicatorBase; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.BuildNumber; import com.intellij.openapi.util.Pair; @@ -89,14 +88,8 @@ public class PluginDownloader { myBuildNumber = buildNumber; } - @SuppressWarnings("UnusedDeclaration") - @Deprecated - public boolean prepareToInstall() throws IOException { - return prepareToInstall(new ProgressIndicatorBase()); - } - - public boolean prepareToInstall(ProgressIndicator pi) throws IOException { - return prepareToInstall(pi, myBuildNumber); + public boolean prepareToInstall(@NotNull ProgressIndicator progressIndicator) throws IOException { + return prepareToInstall(progressIndicator, myBuildNumber); } public boolean prepareToInstall(@Nullable ProgressIndicator progressIndicator, @Nullable BuildNumber forBuildNumber) throws IOException { diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginUpdateInfoDialog.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginUpdateInfoDialog.java index 02e9af1b4118..599f69abf494 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginUpdateInfoDialog.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginUpdateInfoDialog.java @@ -22,6 +22,7 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.util.Ref; import com.intellij.ui.TableUtil; +import com.intellij.util.Consumer; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -67,21 +68,28 @@ class PluginUpdateInfoDialog extends AbstractUpdateDialog { protected void doOKAction() { super.doOKAction(); final Ref result = new Ref(); - final Runnable runnable = new Runnable() { - public void run() { + final Consumer runnable = new Consumer() { + @Override + public void consume(@NotNull ProgressIndicator indicator) { UpdateChecker.saveDisabledToUpdatePlugins(); - result.set(UpdateChecker.install(myUploadedPlugins)); + result.set(UpdateChecker.install(myUploadedPlugins, indicator)); } }; final String progressTitle = "Download plugins..."; if (downloadModal()) { - ProgressManager.getInstance().runProcessWithProgressSynchronously(runnable, progressTitle, true, null); - } else { + ProgressManager.getInstance().run(new Task.Modal(null, progressTitle, true) { + @Override + public void run(@NotNull ProgressIndicator indicator) { + runnable.consume(indicator); + } + }); + } + else { ProgressManager.getInstance().run(new Task.Backgroundable(null, progressTitle, true) { @Override public void run(@NotNull ProgressIndicator indicator) { - runnable.run(); + runnable.consume(indicator); } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java index f3a8f5677371..eb1a454735c1 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java @@ -344,18 +344,18 @@ public final class UpdateChecker { } } - public static boolean checkPluginsHost(final String host, - final Map downloaded, - final boolean collectToUpdate, + public static boolean checkPluginsHost(String host, + Map downloaded, + boolean collectToUpdate, @Nullable ProgressIndicator indicator) throws Exception { return checkPluginsHost(host, downloaded, null, collectToUpdate, indicator, null); } - private static boolean checkPluginsHost(final String host, + private static boolean checkPluginsHost(String host, final Map downloaded, final @Nullable Collection incompatiblePlugins, final boolean collectToUpdate, - final @Nullable ProgressIndicator indicator, + @Nullable ProgressIndicator indicator, final BuildNumber buildNumber) throws Exception { final Document document; try { @@ -740,12 +740,12 @@ public final class UpdateChecker { return ""; } - public static boolean install(Collection downloaders) { + public static boolean install(@NotNull Collection downloaders, @NotNull ProgressIndicator progressIndicator) { boolean installed = false; for (PluginDownloader downloader : downloaders) { if (getDisabledToUpdatePlugins().contains(downloader.getPluginId())) continue; try { - if (downloader.prepareToInstall(ProgressManager.getInstance().getProgressIndicator())) { + if (downloader.prepareToInstall(progressIndicator)) { final IdeaPluginDescriptor descriptor = downloader.getDescriptor(); if (descriptor != null) { InstalledPluginsTableModel.updateExistingPlugin(descriptor, PluginManager.getPlugin(descriptor.getPluginId())); From 67296652b3f692947ae328ef22f19671cf47ffa7 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 12 Nov 2014 14:20:03 +0100 Subject: [PATCH 17/34] cleanup --- .../intellij/util/io/UrlConnectionUtil.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/util/io/UrlConnectionUtil.java b/platform/platform-impl/src/com/intellij/util/io/UrlConnectionUtil.java index 3b1e7049942d..8ea9b536870e 100644 --- a/platform/platform-impl/src/com/intellij/util/io/UrlConnectionUtil.java +++ b/platform/platform-impl/src/com/intellij/util/io/UrlConnectionUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.io; import com.intellij.openapi.application.ApplicationManager; @@ -36,11 +35,10 @@ public class UrlConnectionUtil { private UrlConnectionUtil() { } - public static @Nullable - InputStream getConnectionInputStream(URLConnection connection, @Nullable ProgressIndicator pi) { + public static InputStream getConnectionInputStream(@NotNull URLConnection connection, @Nullable ProgressIndicator progressIndicator) { try { - return getConnectionInputStreamWithException(connection, pi); + return getConnectionInputStreamWithException(connection, progressIndicator); } catch (ProcessCanceledException e) { return null; @@ -50,14 +48,17 @@ public class UrlConnectionUtil { } } + @NotNull + public static InputStream getConnectionInputStreamWithException(@NotNull URLConnection connection, @Nullable ProgressIndicator progressIndicator) throws IOException { + if (ApplicationManager.getApplication() == null) { + return connection.getInputStream(); + } - public static InputStream getConnectionInputStreamWithException(@NotNull URLConnection connection, @Nullable ProgressIndicator pi) - throws IOException { InputStreamGetter getter = new InputStreamGetter(connection); final Future getterFuture = ApplicationManager.getApplication().executeOnPooledThread(getter); while (true) { - if (pi != null) { - pi.checkCanceled(); + if (progressIndicator != null) { + progressIndicator.checkCanceled(); } try { @@ -67,9 +68,9 @@ public class UrlConnectionUtil { catch (TimeoutException ignored) { } - if (pi != null) { - pi.setIndeterminate(true); - pi.setText(pi.getText()); + if (progressIndicator != null) { + progressIndicator.setIndeterminate(true); + progressIndicator.setText(progressIndicator.getText()); } if (getterFuture.isDone()) { From 73c2ce167e0b353e5ca5542206e9e45aa47569e2 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 12 Nov 2014 14:43:24 +0100 Subject: [PATCH 18/34] cleanup --- .../ide/plugins/RepositoryContentHandler.java | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryContentHandler.java b/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryContentHandler.java index a28be60dbf9d..229cf7a0e24e 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryContentHandler.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryContentHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,20 +17,15 @@ package com.intellij.ide.plugins; import com.intellij.openapi.extensions.PluginId; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import java.util.ArrayList; +import java.util.List; import java.util.Stack; -/** - * Created by IntelliJ IDEA. - * User: stathik - * Date: Mar 28, 2003 - * Time: 12:57:45 AM - * To change this template use Options | File Templates. - */ class RepositoryContentHandler extends DefaultHandler { @NonNls public static final String CATEGORY = "category"; @NonNls public static final String IDEA_PLUGIN = "idea-plugin"; @@ -59,23 +54,25 @@ class RepositoryContentHandler extends DefaultHandler { private Stack categoriesStack; + @Override public void startDocument() throws SAXException { plugins = new ArrayList(); categoriesStack = new Stack(); } - public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { + @Override + public void startElement(@NotNull String namespaceURI, @NotNull String localName, @NotNull String qName, @NotNull Attributes attributes) throws SAXException { if (qName.equals(CATEGORY)) { - categoriesStack.push(atts.getValue(NAME)); + categoriesStack.push(attributes.getValue(NAME)); } else if (qName.equals(IDEA_PLUGIN)) { String categoryName = constructCategoryTree(); currentPlugin = new PluginNode(); currentPlugin.setCategory(categoryName); - currentPlugin.setDownloads(atts.getValue(DOWNLOADS)); - currentPlugin.setSize(atts.getValue(SIZE)); - currentPlugin.setUrl(atts.getValue(URL)); - final String dateString = atts.getValue(DATE); + currentPlugin.setDownloads(attributes.getValue(DOWNLOADS)); + currentPlugin.setSize(attributes.getValue(SIZE)); + currentPlugin.setUrl(attributes.getValue(URL)); + final String dateString = attributes.getValue(DATE); if (dateString != null) { currentPlugin.setDate(dateString); } @@ -83,17 +80,18 @@ class RepositoryContentHandler extends DefaultHandler { plugins.add(currentPlugin); } else if (qName.equals(IDEA_VERSION)) { - currentPlugin.setSinceBuild(atts.getValue(SINCE_BUILD)); - currentPlugin.setUntilBuild(atts.getValue(UNTIL_BUILD)); + currentPlugin.setSinceBuild(attributes.getValue(SINCE_BUILD)); + currentPlugin.setUntilBuild(attributes.getValue(UNTIL_BUILD)); } else if (qName.equals(VENDOR)) { - currentPlugin.setVendorEmail(atts.getValue(EMAIL)); - currentPlugin.setVendorUrl(atts.getValue(URL)); + currentPlugin.setVendorEmail(attributes.getValue(EMAIL)); + currentPlugin.setVendorUrl(attributes.getValue(URL)); } currentValue.setLength(0); } - public void endElement(String namespaceURI, String localName, String qName) throws SAXException { + @Override + public void endElement(String namespaceURI, @NotNull String localName, @NotNull String qName) throws SAXException { String currentValueString = currentValue.toString(); currentValue.setLength(0); @@ -129,11 +127,12 @@ class RepositoryContentHandler extends DefaultHandler { } } + @Override public void characters(char[] ch, int start, int length) throws SAXException { currentValue.append(ch, start, length); } - public ArrayList getPluginsList() { + public List getPluginsList() { return plugins; } From e402e8a574cb0e90e7920a007b5301b2cbc0ec9e Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 12 Nov 2014 16:34:02 +0100 Subject: [PATCH 19/34] Use HttpRequests to fix IDEA-131621 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit checkPluginsHost — don't load twice versions info (we still parse it twice) ensure that we download plugin under determinate progress --- .../ide/plugins/RepositoryContentHandler.java | 4 +- .../ide/plugins/RepositoryHelper.java | 42 +---- .../ide/reporter/ConnectionException.java | 31 ---- .../updateSettings/impl/PluginDownloader.java | 78 ++++----- .../updateSettings/impl/UpdateChecker.java | 155 ++++++++---------- .../src/com/intellij/util/HttpRequests.java | 81 ++++++--- .../src/messages/IdeBundle.properties | 1 - 7 files changed, 168 insertions(+), 224 deletions(-) delete mode 100644 platform/platform-impl/src/com/intellij/ide/reporter/ConnectionException.java diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryContentHandler.java b/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryContentHandler.java index 229cf7a0e24e..5629398b47e1 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryContentHandler.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryContentHandler.java @@ -16,6 +16,7 @@ package com.intellij.ide.plugins; import com.intellij.openapi.extensions.PluginId; +import com.intellij.util.containers.Stack; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.xml.sax.Attributes; @@ -24,9 +25,8 @@ import org.xml.sax.helpers.DefaultHandler; import java.util.ArrayList; import java.util.List; -import java.util.Stack; -class RepositoryContentHandler extends DefaultHandler { +public class RepositoryContentHandler extends DefaultHandler { @NonNls public static final String CATEGORY = "category"; @NonNls public static final String IDEA_PLUGIN = "idea-plugin"; @NonNls public static final String NAME = "name"; diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryHelper.java b/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryHelper.java index 1343553a4b7a..0a6262ca4eed 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryHelper.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,7 +39,6 @@ import java.io.*; import java.net.HttpURLConnection; import java.net.URLConnection; import java.util.List; -import java.util.zip.GZIPInputStream; /** * @author stathik @@ -52,24 +51,6 @@ public class RepositoryHelper { return loadPluginsFromRepository(indicator, null); } - @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") - @NotNull - public static InputStream getConnectionInputStream(@NotNull URLConnection connection) throws IOException { - InputStream inputStream = connection.getInputStream(); - if ("gzip".equalsIgnoreCase(connection.getContentEncoding())) { - try { - return new GZIPInputStream(inputStream); - } - catch (IOException e) { - inputStream.close(); - throw e; - } - } - else { - return inputStream; - } - } - @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") public static List loadPluginsFromRepository(@Nullable final ProgressIndicator indicator, @Nullable BuildNumber buildnumber) throws Exception { final ApplicationInfoEx appInfo = ApplicationInfoImpl.getShadowInstance(); @@ -83,6 +64,7 @@ public class RepositoryHelper { final File pluginListFile = new File(PathManager.getPluginsPath(), PLUGIN_LIST_FILE); if (pluginListFile.length() > 0) { try { + //noinspection SpellCheckingInspection url = url + "&crc32=" + Files.hash(pluginListFile, Hashing.crc32()).toString(); } catch (NoSuchMethodError e) { @@ -91,15 +73,12 @@ public class RepositoryHelper { } } - return HttpRequests.request(url).supportGzip(true).get(new ThrowableConvertor, Exception>() { + return HttpRequests.request(url).get(new ThrowableConvertor, Exception>() { @Override public List convert(URLConnection connection) throws Exception { - if (indicator != null) { - indicator.setText2(IdeBundle.message("progress.waiting.for.reply.from.plugin.manager", appInfo.getPluginManagerUrl())); - } - connection.connect(); if (indicator != null) { indicator.checkCanceled(); + indicator.setText2(IdeBundle.message("progress.waiting.for.reply.from.plugin.manager", appInfo.getPluginManagerUrl())); } if (connection instanceof HttpURLConnection && ((HttpURLConnection)connection).getResponseCode() == HttpURLConnection.HTTP_NOT_MODIFIED) { @@ -107,6 +86,7 @@ public class RepositoryHelper { } if (indicator != null) { + indicator.checkCanceled(); indicator.setText2(IdeBundle.message("progress.downloading.list.of.plugins")); } return readPluginsStream(connection, indicator, PLUGIN_LIST_FILE); @@ -114,11 +94,11 @@ public class RepositoryHelper { }); } - private synchronized static List readPluginsStream(@NotNull URLConnection connection, - @Nullable ProgressIndicator indicator, - @NotNull String file) throws Exception { + public synchronized static List readPluginsStream(@NotNull URLConnection connection, + @Nullable ProgressIndicator indicator, + @NotNull String file) throws Exception { File localFile; - InputStream input = getConnectionInputStream(connection); + InputStream input = HttpRequests.getInputStream(connection); try { localFile = createLocalPluginsDescriptions(file); OutputStream output = new FileOutputStream(localFile); @@ -159,10 +139,6 @@ public class RepositoryHelper { return temp; } - public static List loadPluginsFromDescription(@NotNull URLConnection connection, @Nullable ProgressIndicator indicator) throws Exception { - return readPluginsStream(connection, indicator, "host.xml"); - } - public static String getDownloadUrl() { return ApplicationInfoImpl.getShadowInstance().getPluginsDownloadUrl() + "?action=download&id="; } diff --git a/platform/platform-impl/src/com/intellij/ide/reporter/ConnectionException.java b/platform/platform-impl/src/com/intellij/ide/reporter/ConnectionException.java deleted file mode 100644 index 7bd9b76e8d81..000000000000 --- a/platform/platform-impl/src/com/intellij/ide/reporter/ConnectionException.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2000-2009 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.ide.reporter; - -public class ConnectionException extends Exception { - - public ConnectionException(String message) { - super(message); - } - - public ConnectionException(Throwable cause) { - super(cause); - } - - public ConnectionException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java index 3f72c3881164..fd6fce0474f6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/PluginDownloader.java @@ -25,15 +25,15 @@ import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.BuildNumber; -import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.VirtualFileSystem; +import com.intellij.util.Consumer; import com.intellij.util.HttpRequests; import com.intellij.util.PathUtil; -import com.intellij.util.io.UrlConnectionUtil; +import com.intellij.util.ThrowableConvertor; import com.intellij.util.io.ZipUtil; import com.intellij.util.net.NetUtils; import org.jetbrains.annotations.NonNls; @@ -41,7 +41,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.*; -import java.net.HttpURLConnection; import java.net.URLConnection; import java.util.List; @@ -92,7 +91,7 @@ public class PluginDownloader { return prepareToInstall(progressIndicator, myBuildNumber); } - public boolean prepareToInstall(@Nullable ProgressIndicator progressIndicator, @Nullable BuildNumber forBuildNumber) throws IOException { + public boolean prepareToInstall(@NotNull ProgressIndicator progressIndicator, @Nullable BuildNumber forBuildNumber) throws IOException { if (myFile != null) { return true; } @@ -226,65 +225,54 @@ public class PluginDownloader { } } - private File downloadPlugin(@Nullable final ProgressIndicator progressIndicator) throws IOException { - final File pluginsTemp = new File(PathManager.getPluginTempPath()); + @NotNull + private File downloadPlugin(@NotNull final ProgressIndicator progressIndicator) throws IOException { + File pluginsTemp = new File(PathManager.getPluginTempPath()); if (!pluginsTemp.exists() && !pluginsTemp.mkdirs()) { throw new IOException(IdeBundle.message("error.cannot.create.temp.dir", pluginsTemp)); } final File file = FileUtil.createTempFile(pluginsTemp, "plugin_", "_download", true, false); - if (progressIndicator != null) { - progressIndicator.setText(IdeBundle.message("progress.connecting")); - } + progressIndicator.checkCanceled(); + progressIndicator.setText(IdeBundle.message("progress.downloading.plugin", getPluginName())); - URLConnection connection = null; - try { - Pair result = HttpRequests.openConnection(myPluginUrl, false); - if (result.second != null) { - myPluginUrl = result.second; + return HttpRequests.request(myPluginUrl).supportGzip(false).effectiveUrlConsumer(new Consumer() { + @Override + public void consume(String url) { + myPluginUrl = url; } - connection = result.first; + }).get(new ThrowableConvertor() { + @Override + public File convert(URLConnection connection) throws IOException { + progressIndicator.checkCanceled(); - final InputStream is = (ApplicationManager.getApplication() != null) - ? UrlConnectionUtil.getConnectionInputStream(connection, progressIndicator) - : connection.getInputStream(); - if (is == null) { - throw new IOException("Failed to open connection"); - } - - if (progressIndicator != null && ApplicationManager.getApplication() != null) { - progressIndicator.setText(IdeBundle.message("progress.downloading.plugin", getPluginName())); - } - try { - final OutputStream fos = new BufferedOutputStream(new FileOutputStream(file, false)); + InputStream input = HttpRequests.getInputStream(connection); try { - NetUtils.copyStreamContent(progressIndicator, is, fos, connection.getContentLength()); + OutputStream fileOut = new FileOutputStream(file); + try { + NetUtils.copyStreamContent(progressIndicator, input, fileOut, connection.getContentLength()); + } + finally { + fileOut.close(); + } } finally { - fos.close(); + input.close(); } - } - finally { - is.close(); - } - if (myFileName == null) { - myFileName = guessFileName(connection, file); - } + if (myFileName == null) { + myFileName = guessFileName(connection, file); + } - final File newFile = new File(file.getParentFile(), myFileName); - FileUtil.rename(file, newFile); - return newFile; - } - finally { - if (connection instanceof HttpURLConnection) { - ((HttpURLConnection)connection).disconnect(); + File newFile = new File(file.getParentFile(), myFileName); + FileUtil.rename(file, newFile); + return newFile; } - } + }); } @NotNull - private String guessFileName(final URLConnection connection, final File file) throws IOException { + private String guessFileName(@NotNull URLConnection connection, @NotNull File file) throws IOException { String fileName = null; final String contentDisposition = connection.getHeaderField("Content-Disposition"); diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java index eb1a454735c1..e7a069a653e3 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateChecker.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,6 @@ package com.intellij.openapi.updateSettings.impl; import com.intellij.diagnostic.IdeErrorsDialog; import com.intellij.ide.IdeBundle; import com.intellij.ide.plugins.*; -import com.intellij.ide.reporter.ConnectionException; import com.intellij.ide.util.PropertiesComponent; import com.intellij.notification.*; import com.intellij.openapi.application.ApplicationInfo; @@ -30,24 +29,20 @@ import com.intellij.openapi.application.impl.ApplicationInfoImpl; import com.intellij.openapi.diagnostic.IdeaLoggingEvent; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.PluginId; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.progress.Task; +import com.intellij.openapi.progress.*; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.*; +import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.StandardFileSystems; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.Function; -import com.intellij.util.HttpRequests; -import com.intellij.util.PlatformUtils; -import com.intellij.util.ThrowableConvertor; +import com.intellij.util.*; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.io.UrlConnectionUtil; import com.intellij.util.net.HttpConfigurable; +import com.intellij.util.net.NetUtils; import com.intellij.util.ui.UIUtil; import org.jdom.Document; import org.jdom.Element; @@ -58,15 +53,14 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.event.HyperlinkEvent; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; import java.util.*; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; /** * See XML file by {@link com.intellij.openapi.application.ex.ApplicationInfoEx#getUpdateUrls()} for reference. @@ -133,7 +127,6 @@ public final class UpdateChecker { ProgressManager.getInstance().run(new Task.Backgroundable(project, IdeBundle.message("updates.checking.progress"), true) { @Override public void run(@NotNull ProgressIndicator indicator) { - indicator.setIndeterminate(true); doUpdateAndShowResult(project, !fromSettings, true, settings, indicator, null); } @@ -163,7 +156,9 @@ public final class UpdateChecker { settings.setKnownChannelIds(result.getAllChannelsIds()); } else if (result.getState() == UpdateStrategy.State.CONNECTION_ERROR) { - showErrorMessage(manualCheck, IdeBundle.message("updates.error.connection.failed")); + //noinspection ThrowableResultOfMethodCallIgnored + showErrorMessage(manualCheck, + result.getError() instanceof InterruptedIOException ? IdeBundle.message("updates.timeout.error") : IdeBundle.message("updates.error.connection.failed")); return; } @@ -287,7 +282,7 @@ public final class UpdateChecker { if (isReadyToUpdate(pluginId, pluginVersion)) { descriptor = downloader.getDescriptor(); if (descriptor == null) { - if (downloader.prepareToInstall(indicator, buildNumber)) { + if (downloader.prepareToInstall(indicator == null ? new EmptyProgressIndicator() : indicator, buildNumber)) { descriptor = downloader.getDescriptor(); } ourUpdatedPlugins.put(pluginId, downloader); @@ -351,45 +346,74 @@ public final class UpdateChecker { return checkPluginsHost(host, downloaded, null, collectToUpdate, indicator, null); } - private static boolean checkPluginsHost(String host, + private static boolean checkPluginsHost(@NotNull String host, final Map downloaded, final @Nullable Collection incompatiblePlugins, - final boolean collectToUpdate, - @Nullable ProgressIndicator indicator, + boolean collectToUpdate, + @Nullable final ProgressIndicator indicator, final BuildNumber buildNumber) throws Exception { + String url; + if (StandardFileSystems.FILE_PROTOCOL.equals(new URL(host).getProtocol())) { + url = host; + } + else { + url = host + (host.contains("?") ? '&' : '?') + "build=" + ApplicationInfo.getInstance().getBuild().asString(); + } + + BufferExposingByteArrayOutputStream bytes = HttpRequests.request(url) + .get(new ThrowableConvertor() { + @Override + public BufferExposingByteArrayOutputStream convert(URLConnection connection) throws Exception { + InputStream input = HttpRequests.getInputStream(connection); + try { + BufferExposingByteArrayOutputStream output = new BufferExposingByteArrayOutputStream(); + try { + NetUtils.copyStreamContent(indicator, input, output, connection.getContentLength()); + } + finally { + output.close(); + } + return output; + } + finally { + input.close(); + } + } + }); + + ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes.getInternalBuffer(), 0, bytes.size()); final Document document; try { - document = JDOMUtil.loadDocument(RepositoryHelper.getConnectionInputStream(loadVersionInfo(host))); + document = JDOMUtil.loadDocument(inputStream); } catch (JDOMException e) { return false; } + finally { + inputStream.reset(); + } - final List descriptors = RepositoryHelper.loadPluginsFromDescription(loadVersionInfo(host), indicator); - for (IdeaPluginDescriptor descriptor : descriptors) { + SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); + RepositoryContentHandler handler = new RepositoryContentHandler(); + parser.parse(inputStream, handler); + + for (IdeaPluginDescriptor descriptor : handler.getPluginsList()) { ((PluginNode)descriptor).setRepositoryName(host); prepareToInstall(PluginDownloader.createDownloader(descriptor, buildNumber), buildNumber, downloaded, incompatiblePlugins, collectToUpdate, indicator); } boolean success = true; - for (Object plugin : document.getRootElement().getChildren("plugin")) { - final Element pluginElement = (Element)plugin; + for (Element pluginElement : document.getRootElement().getChildren("plugin")) { final String pluginId = pluginElement.getAttributeValue("id"); - final String pluginUrl = pluginElement.getAttributeValue("url"); + String pluginUrl = pluginElement.getAttributeValue("url"); final String pluginVersion = pluginElement.getAttributeValue("version"); - final Element descriptionElement = pluginElement.getChild("description"); - final String description; - if (descriptionElement != null) { - description = descriptionElement.getText(); - } else { - description = null; - } + Element descriptionElement = pluginElement.getChild("description"); + String description = descriptionElement != null ? descriptionElement.getText() : null; - final List dependsPlugins = new ArrayList(); - final List depends = pluginElement.getChildren("depends"); - for (Object depend : depends) { - dependsPlugins.add(PluginId.getId(((Element)depend).getText())); + List dependsPlugins = new SmartList(); + for (Element depend : pluginElement.getChildren("depends")) { + dependsPlugins.add(PluginId.getId(depend.getText())); } if (pluginId == null) { @@ -404,8 +428,10 @@ public final class UpdateChecker { continue; } - final VirtualFile pluginFile = PluginDownloader.findPluginFile(pluginUrl, host); - if (pluginFile == null) continue; + VirtualFile pluginFile = PluginDownloader.findPluginFile(pluginUrl, host); + if (pluginFile == null) { + continue; + } if (collectToUpdate) { final String finalPluginUrl = getPluginUrl(pluginFile); @@ -436,7 +462,8 @@ public final class UpdateChecker { String pluginVersion, BuildNumber buildNumber, Map downloaded, - Collection incompatiblePlugins, boolean collectToUpdate, ProgressIndicator indicator) { + Collection incompatiblePlugins, boolean collectToUpdate, + ProgressIndicator indicator) { try { if (indicator != null) { indicator.setText2(finalPluginUrl); @@ -463,7 +490,7 @@ public final class UpdateChecker { } @Nullable - private static UpdatesInfo loadUpdatesInfo(@Nullable final String updateUrl) throws Exception { + private static UpdatesInfo loadUpdatesInfo(@Nullable String updateUrl) throws Exception { if (LOG.isDebugEnabled()) { LOG.debug("load update xml (UPDATE_URL='" + updateUrl + "' )"); } @@ -477,7 +504,7 @@ public final class UpdateChecker { .get(new ThrowableConvertor() { @Override public UpdatesInfo convert(URLConnection connection) throws Exception { - InputStream inputStream = connection.getInputStream(); + InputStream inputStream = HttpRequests.getInputStream(connection); try { return new UpdatesInfo(JDOMUtil.loadDocument(inputStream).getRootElement()); } @@ -502,9 +529,6 @@ public final class UpdateChecker { return new CheckForUpdateResult(UpdateStrategy.State.NOTHING_LOADED); } } - catch (InterruptedIOException e) { - return new CheckForUpdateResult(UpdateStrategy.State.CONNECTION_ERROR, new ConnectionException(IdeBundle.message("updates.timeout.error"))); - } catch (Exception e) { return new CheckForUpdateResult(UpdateStrategy.State.CONNECTION_ERROR, e); } @@ -645,49 +669,6 @@ public final class UpdateChecker { } } - @NotNull - private static URLConnection loadVersionInfo(@NotNull final String url) throws Exception { - final Ref connectionRef = Ref.create(); - final Ref exception = Ref.create(); - Future downloadThreadFuture = ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { - @Override - public void run() { - try { - String urlToCheck; - if (!StandardFileSystems.FILE_PROTOCOL.equals(new URL(url).getProtocol())) { - urlToCheck = url + (url.contains("?") ? "&" : "?") + "build=" + ApplicationInfo.getInstance().getBuild().asString(); - } - else { - urlToCheck = url; - } - - URLConnection connection = HttpRequests.openConnection(urlToCheck, true).first; - connection.connect(); - connectionRef.set(connection); - } - catch (IOException e) { - exception.set(e); - } - } - }); - - try { - downloadThreadFuture.get(5, TimeUnit.SECONDS); - } - catch (TimeoutException ignored) { - } - - if (!downloadThreadFuture.isDone()) { - downloadThreadFuture.cancel(true); - throw new ConnectionException(IdeBundle.message("updates.timeout.error")); - } - - if (!exception.isNull()) { - throw exception.get(); - } - return connectionRef.get(); - } - public static String getInstallationUID(final PropertiesComponent propertiesComponent) { if (SystemInfo.isWindows) { String uid = getInstallationUIDOnWindows(propertiesComponent); diff --git a/platform/platform-impl/src/com/intellij/util/HttpRequests.java b/platform/platform-impl/src/com/intellij/util/HttpRequests.java index 38cf8682a8fb..9bc99d1d5208 100644 --- a/platform/platform-impl/src/com/intellij/util/HttpRequests.java +++ b/platform/platform-impl/src/com/intellij/util/HttpRequests.java @@ -17,25 +17,29 @@ package com.intellij.util; import com.intellij.ide.IdeBundle; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.util.ClassLoaderUtil; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.ThrowableComputable; import com.intellij.util.net.HttpConfigurable; import org.jetbrains.annotations.NotNull; import java.io.IOException; +import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLClassLoader; import java.net.URLConnection; +import java.util.zip.GZIPInputStream; +/** + * GZip supported by default, so, you must use {@link #getInputStream(java.net.URLConnection)} to get connection input stream. + */ public final class HttpRequests { public static class HttpRequestBuilder { private final String url; private int connectTimeout = HttpConfigurable.CONNECTION_TIMEOUT; private int readTimeout = HttpConfigurable.CONNECTION_TIMEOUT; - private boolean supportGzip; + private Consumer effectiveUrlConsumer; + + private boolean supportGzip = true; private HttpRequestBuilder(@NotNull String url) { this.url = url; @@ -47,6 +51,7 @@ public final class HttpRequests { return this; } + @SuppressWarnings("unused") @NotNull public HttpRequestBuilder readTimeout(int value) { readTimeout = value; @@ -59,7 +64,13 @@ public final class HttpRequests { return this; } - public T get(@NotNull final ThrowableConvertor handler) throws Exception { + @NotNull + public HttpRequestBuilder effectiveUrlConsumer(Consumer value) { + effectiveUrlConsumer = value; + return this; + } + + public T get(@NotNull final ThrowableConvertor handler) throws E, IOException { return loadData(this, handler); } } @@ -69,30 +80,46 @@ public final class HttpRequests { return new HttpRequestBuilder(url); } - private static T loadData(@NotNull final HttpRequestBuilder requestBuilder, @NotNull final ThrowableConvertor handler) throws Exception { - return ClassLoaderUtil.runWithClassLoader(new URLClassLoader(new URL[0], Thread.currentThread().getContextClassLoader()), new ThrowableComputable() { - @Override - public T compute() throws Exception { - URLConnection connection = openConnection(requestBuilder.url, requestBuilder.supportGzip).first; - try { - return handler.convert(connection); - } - finally { - if (connection instanceof HttpURLConnection) { - ((HttpURLConnection)connection).disconnect(); - } + @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") + @NotNull + public static InputStream getInputStream(@NotNull URLConnection connection) throws IOException { + InputStream inputStream = connection.getInputStream(); + if ("gzip".equalsIgnoreCase(connection.getContentEncoding())) { + try { + return new GZIPInputStream(inputStream); + } + catch (IOException e) { + inputStream.close(); + throw e; + } + } + else { + return inputStream; + } + } + + private static T loadData(@NotNull HttpRequestBuilder requestBuilder, @NotNull ThrowableConvertor handler) + throws E, IOException { + ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(new URLClassLoader(new URL[0], oldClassLoader)); + try { + URLConnection connection = openConnection(requestBuilder); + try { + return handler.convert(connection); + } + finally { + if (connection instanceof HttpURLConnection) { + ((HttpURLConnection)connection).disconnect(); } } - }); + } + finally { + Thread.currentThread().setContextClassLoader(oldClassLoader); + } } @NotNull - public static Pair openConnection(@NotNull String initialUrl, boolean supportGzip) throws IOException { - return openConnection(request(initialUrl).supportGzip(supportGzip)); - } - - @NotNull - private static Pair openConnection(@NotNull HttpRequestBuilder requestBuilder) throws IOException { + private static URLConnection openConnection(@NotNull HttpRequestBuilder requestBuilder) throws IOException { int i = 0; String url = requestBuilder.url; while (i++ < 99) { @@ -132,7 +159,11 @@ public final class HttpRequests { } } } - return Pair.create(connection, url == requestBuilder.url ? null : url); + + if (url != requestBuilder.url && requestBuilder.effectiveUrlConsumer != null) { + requestBuilder.effectiveUrlConsumer.consume(url); + } + return connection; } throw new IOException("Infinite redirection"); } diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties index e0561fb7c788..0eb3fbde6b09 100644 --- a/platform/platform-resources-en/src/messages/IdeBundle.properties +++ b/platform/platform-resources-en/src/messages/IdeBundle.properties @@ -531,7 +531,6 @@ button.http.proxy.settings=&HTTP Proxy Settings... group.vendor=Vendor plugin.status.installed=Installed progress.waiting.for.reply.from.plugin.manager=Waiting for reply from {0} -progress.connecting=Connecting... progress.downloading.plugin=Downloading plugin ''{0}'' error.cannot.create.temp.dir=Unable to create temp directory ''{0}'' error.connection.failed.with.http.code.N=Connection failed with HTTP code {0} From e7f20c88420a564f03c9208d1a6b3317cdaf503c Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 12 Nov 2014 16:34:19 +0100 Subject: [PATCH 20/34] cleanup --- .../src/com/intellij/util/net/NetUtils.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/platform/platform-api/src/com/intellij/util/net/NetUtils.java b/platform/platform-api/src/com/intellij/util/net/NetUtils.java index b01d4db1f1cb..7e8e5b65c6e9 100644 --- a/platform/platform-api/src/com/intellij/util/net/NetUtils.java +++ b/platform/platform-api/src/com/intellij/util/net/NetUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.intellij.util.net; import com.intellij.Patches; @@ -193,15 +192,17 @@ public class NetUtils { * @throws com.intellij.openapi.progress.ProcessCanceledException if process was canceled. */ public static int copyStreamContent(@Nullable ProgressIndicator indicator, - InputStream inputStream, - OutputStream outputStream, + @NotNull InputStream inputStream, + @NotNull OutputStream outputStream, int expectedContentSize) throws IOException, ProcessCanceledException { if (indicator != null) { indicator.checkCanceled(); - if (expectedContentSize < 0) indicator.setIndeterminate(true); + if (expectedContentSize < 0) { + indicator.setIndeterminate(true); + } } - final byte[] buffer = new byte[4 * 1024]; + final byte[] buffer = new byte[8 * 1024]; int count; int total = 0; while ((count = inputStream.read(buffer)) > 0) { From d7ffaf6d680547011aac618c9f4f04c2271cc78f Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 12 Nov 2014 12:42:12 +0100 Subject: [PATCH 21/34] paste reference: don't insert double parentheses --- .../ide/actions/JavaQualifiedNameProvider.java | 4 +++- .../codeInsight/CopyReferenceTest.groovy | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/java/java-impl/src/com/intellij/ide/actions/JavaQualifiedNameProvider.java b/java/java-impl/src/com/intellij/ide/actions/JavaQualifiedNameProvider.java index 4bccec21ec7e..da011319c80f 100644 --- a/java/java-impl/src/com/intellij/ide/actions/JavaQualifiedNameProvider.java +++ b/java/java-impl/src/com/intellij/ide/actions/JavaQualifiedNameProvider.java @@ -180,7 +180,9 @@ public class JavaQualifiedNameProvider implements QualifiedNameProvider { toInsert = targetElement.getName(); if (targetElement instanceof PsiMethod) { - suffix = "()"; + if (!fqn.contains("(")) { + suffix = "()"; + } if (((PsiMethod)targetElement).isConstructor()) { targetElement = targetElement.getContainingClass(); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/CopyReferenceTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/CopyReferenceTest.groovy index 3b4929d874a4..a5ef7e03d287 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/CopyReferenceTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/CopyReferenceTest.groovy @@ -74,6 +74,24 @@ class Foo { performPaste() myFixture.checkResult "/** Foo#foo(java.util.List) */" } + + public void "test paste overloaded signature to a comment"() { + myFixture.configureByText "a.java", """ +class Foo { + void foo(int a) {} // + void foo(int a, int b) {} +} +""" + performCopy() + myFixture.editor.caretModel.moveToOffset(myFixture.editor.document.text.indexOf('//') + 2) + performPaste() + myFixture.checkResult """ +class Foo { + void foo(int a) {} //Foo.foo(int) + void foo(int a, int b) {} +} +""" + } public void testFqnInImport() { myFixture.addClass("package foo; public class Foo {}") From 061e993f1f05cd7aa4bb419574993121fd230109 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 12 Nov 2014 15:13:06 +0100 Subject: [PATCH 22/34] avoid PIEAE right after stub-psi mismatch in another thread (EA-58325, EA-56774) --- .../extapi/psi/StubBasedPsiElementBase.java | 12 +++++++++- .../intellij/psi/impl/source/PsiFileImpl.java | 24 +++++++++++-------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/platform/core-impl/src/com/intellij/extapi/psi/StubBasedPsiElementBase.java b/platform/core-impl/src/com/intellij/extapi/psi/StubBasedPsiElementBase.java index 59b6533f4242..809bd9fcafb0 100644 --- a/platform/core-impl/src/com/intellij/extapi/psi/StubBasedPsiElementBase.java +++ b/platform/core-impl/src/com/intellij/extapi/psi/StubBasedPsiElementBase.java @@ -23,6 +23,7 @@ import com.intellij.lang.ASTNode; import com.intellij.lang.Language; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicatorProvider; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; @@ -179,7 +180,16 @@ public class StubBasedPsiElementBase extends ASTDelegateP ApplicationManager.getApplication().assertReadAccessAllowed(); synchronized (PsiLock.LOCK) { if (myStub != null) { - throw new PsiInvalidElementAccessException(this, "no psi for file stub " + stub + ", invalidation reason=" + ((PsiFileStubImpl) stub).getInvalidationReason(), null); + String reason = ((PsiFileStubImpl)stub).getInvalidationReason(); + PsiInvalidElementAccessException exception = + new PsiInvalidElementAccessException(this, "no psi for file stub " + stub + ", invalidation reason=" + reason, null); + if (PsiFileImpl.STUB_PSI_MISMATCH.equals(reason)) { + // we're between finding stub-psi mismatch and the next EDT spot where the file is reparsed and stub rebuilt + // see com.intellij.psi.impl.source.PsiFileImpl.rebuildStub() + // most likely it's just another highlighting thread accessing the same PSI concurrently and not yet canceled, so cancel it + throw new ProcessCanceledException(exception); + } + throw exception; } } } diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java index dabb45cd7667..bdbbc364aa60 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java @@ -53,6 +53,7 @@ import com.intellij.psi.tree.ILazyParseableElementType; import com.intellij.psi.tree.IStubFileElementType; import com.intellij.psi.tree.TokenSet; import com.intellij.reference.SoftReference; +import com.intellij.util.FileContentUtilCore; import com.intellij.util.IncorrectOperationException; import com.intellij.util.PatchedWeakReference; import com.intellij.util.containers.ContainerUtil; @@ -67,6 +68,7 @@ import java.util.*; public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiFileWithStubSupport, Queryable { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.PsiFileImpl"); + public static final String STUB_PSI_MISMATCH = "stub-psi mismatch"; private IElementType myElementType; protected IElementType myContentElementType; @@ -299,7 +301,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF protected void reportStubAstMismatch(String message, StubTree stubTree, Document cachedDocument) { rebuildStub(); - clearStub("stub-psi mismatch"); + clearStub(STUB_PSI_MISMATCH); scheduleDropCachesWithInvalidStubPsi(); String msg = message; @@ -1007,21 +1009,23 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF } private void rebuildStub() { - final VirtualFile vFile = getVirtualFile(); + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + myManager.dropResolveCaches(); - if (vFile != null && vFile.isValid()) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { + final VirtualFile vFile = getVirtualFile(); + if (vFile != null && vFile.isValid()) { final Document doc = FileDocumentManager.getInstance().getCachedDocument(vFile); if (doc != null) { FileDocumentManager.getInstance().saveDocument(doc); } - } - }, ModalityState.NON_MODAL); - StubTreeLoader.getInstance().rebuildStubTree(vFile); - } + FileContentUtilCore.reparseFiles(vFile); + StubTreeLoader.getInstance().rebuildStubTree(vFile); + } + } + }, ModalityState.NON_MODAL); } @Override From 4b131d7ca226b4cb1d4f8f7a27cb3748acfa597b Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 12 Nov 2014 17:07:53 +0100 Subject: [PATCH 23/34] VirtualDirectoryImpl: remove easy garbage --- .../openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java index b832ae9eb455..5b9d83d0a222 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java @@ -117,7 +117,9 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { // in this case we should remove it from there removeFromArray(indexInReal); } - assertConsistency(ignoreCase, name); + if (CHECK) { + assertConsistency(ignoreCase, name); + } } @Nullable // null if there can't be a child with this name, NULL_VIRTUAL_FILE From d4ee280dcfcd005235401c939ac1ef063f79d8ec Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 12 Nov 2014 17:14:07 +0100 Subject: [PATCH 24/34] goto symbol optimization: avoid using hierarchical findMethodsByName --- .../DefaultSymbolNavigationContributor.java | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultSymbolNavigationContributor.java b/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultSymbolNavigationContributor.java index 24ada216c0d9..00c9967fdcd4 100644 --- a/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultSymbolNavigationContributor.java +++ b/java/java-impl/src/com/intellij/ide/util/gotoByName/DefaultSymbolNavigationContributor.java @@ -30,6 +30,7 @@ import com.intellij.psi.impl.PsiSuperMethodImplUtil; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.PsiSearchScopeUtil; import com.intellij.psi.search.PsiShortNamesCache; +import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.Processor; @@ -89,19 +90,24 @@ public class DefaultSymbolNavigationContributor implements ChooseByNameContribut return member.getContainingFile().getVirtualFile() != null; } - private static boolean hasSuperMethod(PsiMethod method, GlobalSearchScope scope, Condition qualifiedMatcher) { - PsiClass containingClass = method.getContainingClass(); + private static boolean hasSuperMethod(final PsiMethod method, final GlobalSearchScope scope, final Condition qualifiedMatcher) { + final PsiClass containingClass = method.getContainingClass(); if (containingClass == null) return false; - for (PsiMethod candidate : containingClass.findMethodsByName(method.getName(), true)) { - if (candidate.getContainingClass() != containingClass && - PsiSearchScopeUtil.isInScope(scope, candidate) && - qualifiedMatcher.value(candidate) && - PsiSuperMethodImplUtil.isSuperMethodSmart(method, candidate)) { + // avoid using hierarchical findMethodsByName because we only want to check the given method hierarchy, without its siblings + return !InheritanceUtil.processSupers(containingClass, false, new Processor() { + @Override + public boolean process(PsiClass superClass) { + if (PsiSearchScopeUtil.isInScope(scope, superClass)) { + for (PsiMethod candidate : superClass.findMethodsByName(method.getName(), false)) { + if (qualifiedMatcher.value(candidate) && PsiSuperMethodImplUtil.isSuperMethodSmart(method, candidate)) { + return false; + } + } + } return true; } - } - return false; + }); } public void processNames(@NotNull Processor processor, @NotNull GlobalSearchScope scope, @Nullable IdFilter filter) { From 85aa1fed1cdd13178868662fb6ff2d9cb7594979 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 12 Nov 2014 17:22:46 +0100 Subject: [PATCH 25/34] fix XmlUnusedNamespaceInspection CCE --- .../daemon/impl/analysis/XmlUnusedNamespaceInspection.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xml/xml-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/XmlUnusedNamespaceInspection.java b/xml/xml-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/XmlUnusedNamespaceInspection.java index 9d77c11fa90b..046a172ab11f 100644 --- a/xml/xml-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/XmlUnusedNamespaceInspection.java +++ b/xml/xml-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/XmlUnusedNamespaceInspection.java @@ -53,7 +53,10 @@ public class XmlUnusedNamespaceInspection extends XmlSuppressableInspectionTool return new XmlElementVisitor() { @Override public void visitXmlAttribute(XmlAttribute attribute) { - XmlRefCountHolder refCountHolder = XmlRefCountHolder.getRefCountHolder((XmlFile)holder.getFile()); + PsiFile file = holder.getFile(); + if (!(file instanceof XmlFile)) return; + + XmlRefCountHolder refCountHolder = XmlRefCountHolder.getRefCountHolder((XmlFile)file); if (refCountHolder == null) return; if (!attribute.isNamespaceDeclaration()) { checkUnusedLocations(attribute, holder, refCountHolder); From 8318527632bf4ded8b4f6f8d3d254cb11e040163 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Wed, 12 Nov 2014 20:12:29 +0300 Subject: [PATCH 26/34] fixed variables view flickering if conditional breakpoint is evaluating --- .../intellij/debugger/impl/DebuggerSession.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java index 26d0820fedc9..574377e84b87 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java @@ -671,14 +671,15 @@ public class DebuggerSession implements AbstractDebuggerSession { @Override public void evaluationFinished(final SuspendContextImpl context) { myIsEvaluating = false; - DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() { - @Override - public void run() { - if (context != getSuspendContext()) { - getContextManager().setState(DebuggerContextUtil.createDebuggerContext(DebuggerSession.this, context), STATE_PAUSED, EVENT_REFRESH, null); - } - } - }); + // seems to be not required after move to xdebugger + //DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() { + // @Override + // public void run() { + // if (context != getSuspendContext()) { + // getContextManager().setState(DebuggerContextUtil.createDebuggerContext(DebuggerSession.this, context), STATE_PAUSED, EVENT_REFRESH, null); + // } + // } + //}); } } From 6aab4155a735c807af7be977fa7af7441f93373c Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Wed, 12 Nov 2014 20:17:22 +0300 Subject: [PATCH 27/34] IDEA-111466 Mac OS X keyboard shortcuts with alt don't work under Oracle Java 7 --- .../com/intellij/openapi/MnemonicHelper.java | 50 ++++++++++++++----- .../util/resources/misc/registry.properties | 2 +- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/MnemonicHelper.java b/platform/platform-api/src/com/intellij/openapi/MnemonicHelper.java index 8c38dfd652ff..91f0eb438e56 100644 --- a/platform/platform-api/src/com/intellij/openapi/MnemonicHelper.java +++ b/platform/platform-api/src/com/intellij/openapi/MnemonicHelper.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi; +import com.intellij.ide.ui.UISettings; import com.intellij.openapi.actionSystem.CustomShortcutSet; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.SystemInfo; @@ -25,10 +26,13 @@ import com.intellij.util.ui.DialogUtil; import org.jetbrains.annotations.NonNls; import javax.swing.*; +import javax.swing.text.JTextComponent; import java.awt.*; +import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; @@ -65,24 +69,32 @@ public class MnemonicHelper extends ComponentTreeWatcher { abstractButton.addPropertyChangeListener(AbstractButton.TEXT_CHANGED_PROPERTY, TEXT_LISTENER); DialogUtil.registerMnemonic(abstractButton); checkForDuplicateMnemonics(abstractButton); + fixMacMnemonicKeyStroke(abstractButton, null); + } else if (parentComponent instanceof JTextComponent) { + if (SystemInfo.isMac) { + parentComponent.enableInputMethods(UISettings.getShadowInstance().DISABLE_MNEMONICS_IN_CONTROLS); + } } else if (parentComponent instanceof JLabel) { final JLabel jLabel = ((JLabel)parentComponent); jLabel.addPropertyChangeListener(TEXT_CHANGED_PROPERTY, TEXT_LISTENER); DialogUtil.registerMnemonic(jLabel, null); checkForDuplicateMnemonics(jLabel); - if (SystemInfo.isMac) { - // hack to make Labels mnemonic work for ALT+KEY_CODE on Macs. - // Default implementation uses ALT+CTRL+KEY_CODE (see BasicLabelUI). - final InputMap inputMap = jLabel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); - if (inputMap != null) { - final KeyStroke[] strokes = inputMap.allKeys(); - if (strokes != null) { - for (KeyStroke stroke : strokes) { - final int m = stroke.getModifiers(); - // to be sure if default mnemonic exist - if (((m & KeyEvent.ALT_MASK) == KeyEvent.ALT_MASK) && ((m & KeyEvent.CTRL_MASK) == KeyEvent.CTRL_MASK)) { - inputMap.put(KeyStroke.getKeyStroke(stroke.getKeyCode(), KeyEvent.ALT_MASK), "release"); // "release" only is OK - } + fixMacMnemonicKeyStroke(jLabel, "release"); // "release" only is OK for labels + } + } + + private static void fixMacMnemonicKeyStroke(JComponent component, String type) { + if (SystemInfo.isMac) { + // hack to make component's mnemonic work for ALT+KEY_CODE on Macs. + // Default implementation uses ALT+CTRL+KEY_CODE (see BasicLabelUI). + InputMap inputMap = component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); + if (inputMap != null) { + KeyStroke[] strokes = inputMap.allKeys(); + if (strokes != null) { + int mask = KeyEvent.ALT_MASK | KeyEvent.CTRL_MASK; + for (KeyStroke stroke : strokes) { + if (mask == (mask & stroke.getModifiers())) { + inputMap.put(getKeyStrokeWithoutCtrlModifier(stroke), type != null ? type : inputMap.get(stroke)); } } } @@ -90,6 +102,18 @@ public class MnemonicHelper extends ComponentTreeWatcher { } } + private static KeyStroke getKeyStrokeWithoutCtrlModifier(KeyStroke stroke) { + try { + Method method = AWTKeyStroke.class.getDeclaredMethod("getCachedStroke", char.class, int.class, int.class, boolean.class); + method.setAccessible(true); + int modifiers = stroke.getModifiers() & ~InputEvent.CTRL_MASK & ~InputEvent.CTRL_DOWN_MASK; + return (KeyStroke)method.invoke(null, stroke.getKeyChar(), stroke.getKeyCode(), modifiers, stroke.isOnKeyRelease()); + } + catch (Exception exception) { + throw new IllegalStateException(exception); + } + } + protected void unprocessComponent(Component component) { } diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index e3901a2be674..43573dbd796f 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -454,7 +454,7 @@ commonjs.complete.required.filename.with.extension=false commonjs.complete.required.filename.with.extension.description=If checked, required filenames are completed with extension -fix.jdk7.alt.shortcuts=true +fix.jdk7.alt.shortcuts=false fix.jdk7.alt.shortcuts.description=Allow to use alt for shortcuts on MacOSX with jdk7+ spy.js.realtime.evaluation=false From 997ab59e7433d6f8d026f9cc07cac726e894b2ab Mon Sep 17 00:00:00 2001 From: Konstantin Kolosovsky Date: Wed, 12 Nov 2014 20:29:56 +0300 Subject: [PATCH 28/34] IDEA-104940 Fixed multi-threading issues while incrementally displaying file history to the user - use single thread for creating and scheduling to display partial history sessions (to prevent cases where less complete history sessions are scheduled to display after more complete history sessions - and so user sees incorrect results) --- .../intellij/util/BufferedListConsumer.java | 38 ++++++++++++------- .../history/FileHistorySessionPartner.java | 16 +++++++- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/util/BufferedListConsumer.java b/platform/platform-impl/src/com/intellij/util/BufferedListConsumer.java index 857c300281cd..7d563f4fc517 100644 --- a/platform/platform-impl/src/com/intellij/util/BufferedListConsumer.java +++ b/platform/platform-impl/src/com/intellij/util/BufferedListConsumer.java @@ -16,6 +16,7 @@ package com.intellij.util; import com.intellij.openapi.application.ApplicationManager; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; @@ -72,23 +73,32 @@ public class BufferedListConsumer implements Consumer> { synchronized (myFlushLock) { if (myPendingFlush || myBuffer.isEmpty()) return; myPendingFlush = true; - ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { - @Override - public void run() { - myTs = ts; - final List list; - synchronized (myFlushLock) { - myPendingFlush = false; - if (myBuffer.isEmpty()) return; - list = myBuffer; - myBuffer = new ArrayList(mySize); - } - myConsumer.consume(list); - } - }); + invokeConsumer(createConsumerRunnable(ts)); } } + protected void invokeConsumer(@NotNull Runnable consumerRunnable) { + ApplicationManager.getApplication().executeOnPooledThread(consumerRunnable); + } + + @NotNull + private Runnable createConsumerRunnable(final long ts) { + return new Runnable() { + @Override + public void run() { + myTs = ts; + final List list; + synchronized (myFlushLock) { + myPendingFlush = false; + if (myBuffer.isEmpty()) return; + list = myBuffer; + myBuffer = new ArrayList(mySize); + } + myConsumer.consume(list); + } + }; + } + public void flush() { flushImpl(System.currentTimeMillis()); if (myFlushListener != null) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistorySessionPartner.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistorySessionPartner.java index 6c9a6c25487c..147bba389a17 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistorySessionPartner.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistorySessionPartner.java @@ -33,6 +33,7 @@ import com.intellij.ui.content.ContentManager; import com.intellij.util.BufferedListConsumer; import com.intellij.util.Consumer; import com.intellij.util.ContentsUtil; +import org.jetbrains.annotations.NotNull; import java.util.List; @@ -63,8 +64,10 @@ public class FileHistorySessionPartner implements VcsAppendableHistorySessionPar myRepositoryPath = repositoryPath; myVcs = vcs; myRefresherI = refresherI; - myBuffer = new BufferedListConsumer(5, new Consumer>() { + Consumer> sessionRefresher = new Consumer>() { public void consume(List vcsFileRevisions) { + // TODO: Logic should be revised to we could just append some revisions to history panel instead of creating and showing new history + // TODO: session mySession.getRevisionList().addAll(vcsFileRevisions); final VcsHistorySession copy = mySession.copyWithCachedRevision(); ApplicationManager.getApplication().invokeLater(new Runnable() { @@ -73,7 +76,16 @@ public class FileHistorySessionPartner implements VcsAppendableHistorySessionPar } }); } - }, 1000); + }; + myBuffer = new BufferedListConsumer(5, sessionRefresher, 1000) { + @Override + protected void invokeConsumer(@NotNull Runnable consumerRunnable) { + // Do not invoke in arbitrary background thread as due to parallel execution this could lead to cases when invokeLater() (from + // sessionRefresher) is scheduled at first for history session with (as an example) 10 revisions (new buffered list) and then with + // 5 revisions (previous buffered list). And so incorrect UI is shown to the user. + consumerRunnable.run(); + } + }; } public void acceptRevision(VcsFileRevision revision) { From 78b4871d51b05fe2218cf6866d0b14a27bef8416 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 12 Nov 2014 18:42:35 +0100 Subject: [PATCH 29/34] IDEA-130959 (indicator passing reverted - causes premature task end) --- .../application/ex/ApplicationUtil.java | 24 +++++--------- .../openapi/fileEditor/impl/LoadTextUtil.java | 2 +- .../java/decompiler/IdeaDecompilerTest.java | 33 ------------------- 3 files changed, 10 insertions(+), 49 deletions(-) diff --git a/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationUtil.java b/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationUtil.java index a864652c503b..c7cf4a8da64c 100644 --- a/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationUtil.java +++ b/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationUtil.java @@ -17,7 +17,6 @@ package com.intellij.openapi.application.ex; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Ref; @@ -54,30 +53,25 @@ public class ApplicationUtil { * Allows to interrupt a process which does not performs checkCancelled() calls by itself. * Note that the process may continue to run in background indefinitely - so avoid using this method unless absolutely needed. */ - public static T runWithCheckCanceled(@NotNull final Callable callable, @NotNull final ProgressIndicator indicator) throws Exception { + public static T runWithCheckCanceled(@NotNull final Callable callable) throws Exception { final Ref error = Ref.create(); Future future = ApplicationManager.getApplication().executeOnPooledThread(new Callable() { @Override public T call() throws Exception { - return ProgressManager.getInstance().runProcess(new Computable() { - @Override - public T compute() { - try { - return callable.call(); - } - catch (Throwable t) { - error.set(t); - return null; - } - } - }, indicator); + try { + return callable.call(); + } + catch (Throwable t) { + error.set(t); + return null; + } } }); while (true) { try { - indicator.checkCanceled(); + ProgressManager.checkCanceled(); } catch (ProcessCanceledException e) { future.cancel(true); diff --git a/platform/core-impl/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java b/platform/core-impl/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java index 6f1d24e4a8c3..ca194dd5ce65 100644 --- a/platform/core-impl/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java +++ b/platform/core-impl/src/com/intellij/openapi/fileEditor/impl/LoadTextUtil.java @@ -390,7 +390,7 @@ public final class LoadTextUtil { public CharSequence call() { return decompiler.decompile(file); } - }, indicator)); + })); } catch (Throwable t) { error.set(t); diff --git a/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java b/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java index ac7d27057348..81df4dd82859 100644 --- a/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java +++ b/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java @@ -18,12 +18,8 @@ package org.jetbrains.java.decompiler; import com.intellij.codeInsight.daemon.impl.IdentifierHighlighterPassFactory; import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction; import com.intellij.debugger.PositionManager; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.PluginPathManager; -import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.StdFileTypes; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.registry.Registry; @@ -32,11 +28,9 @@ import com.intellij.openapi.vfs.*; import com.intellij.pom.Navigatable; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; -import com.intellij.psi.compiled.ClassFileDecompilers; import com.intellij.psi.impl.compiled.ClsFileImpl; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; -import com.intellij.util.Alarm; import com.intellij.util.ThrowableRunnable; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.io.URLUtil; @@ -175,31 +169,4 @@ public class IdeaDecompilerTest extends LightCodeInsightFixtureTestCase { } }).cpuBound().assertTiming(); } - - public void testCancellation() { - VirtualFile file = getTestFile(PlatformTestUtil.getRtJarPath() + "!/javax/swing/JTable.class"); - - final IdeaDecompiler decompiler = (IdeaDecompiler)ClassFileDecompilers.find(file); - assertNotNull(decompiler); - - final Alarm alarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, getProject()); - alarm.addRequest(new Runnable() { - @Override - public void run() { - ProgressIndicator progress = decompiler.getProgress(); - if (progress != null) { - progress.cancel(); - } - else { - alarm.addRequest(this, 200, ModalityState.any()); - } - } - }, 750, ModalityState.any()); - - try { - FileDocumentManager.getInstance().getDocument(file); - fail("should have been cancelled"); - } - catch (ProcessCanceledException ignored) { } - } } From 4fd6842ba010910fdf9c1cdeb4bc8571948c8595 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 12 Nov 2014 18:46:04 +0100 Subject: [PATCH 30/34] Cleanup (dead code) --- .../jetbrains/java/decompiler/IdeaDecompiler.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.java b/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.java index 098cc7c6667a..b67f88b8b1ed 100644 --- a/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.java +++ b/plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.java @@ -27,8 +27,6 @@ import com.intellij.openapi.application.ex.ApplicationManagerEx; import com.intellij.openapi.fileEditor.*; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.DefaultProjectFactory; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; @@ -49,7 +47,6 @@ import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.TestOnly; import org.jetbrains.java.decompiler.main.decompiler.BaseDecompiler; import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider; import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; @@ -77,7 +74,6 @@ public class IdeaDecompiler extends ClassFileDecompilers.Light { private final IFernflowerLogger myLogger = new IdeaLogger(); private final Map myOptions = new HashMap(); private boolean myLegalNoticeAccepted; - private volatile ProgressIndicator myProgress; public IdeaDecompiler() { myOptions.put(IFernflowerPreferences.HIDE_DEFAULT_CONSTRUCTOR, "0"); @@ -144,8 +140,6 @@ public class IdeaDecompiler extends ClassFileDecompilers.Light { return ClsFileImpl.decompile(file); } - myProgress = ProgressManager.getInstance().getProgressIndicator(); - try { Map files = ContainerUtil.newLinkedHashMap(); files.put(file.getPath(), file); @@ -199,15 +193,6 @@ public class IdeaDecompiler extends ClassFileDecompilers.Light { throw new CannotDecompileException(e); } } - finally { - myProgress = null; - } - } - - @TestOnly - @Nullable - public ProgressIndicator getProgress() { - return myProgress; } private static class MyBytecodeProvider implements IBytecodeProvider { From 28639925863e2b07ee8ca8573a14cbfe286916cd Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 12 Nov 2014 19:10:38 +0100 Subject: [PATCH 31/34] MemberInfoBase: use ensureValid --- .../com/intellij/refactoring/classMembers/MemberInfoBase.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/lang-api/src/com/intellij/refactoring/classMembers/MemberInfoBase.java b/platform/lang-api/src/com/intellij/refactoring/classMembers/MemberInfoBase.java index 1ddbf5a65d83..74782538c2ca 100644 --- a/platform/lang-api/src/com/intellij/refactoring/classMembers/MemberInfoBase.java +++ b/platform/lang-api/src/com/intellij/refactoring/classMembers/MemberInfoBase.java @@ -18,6 +18,7 @@ package com.intellij.refactoring.classMembers; import com.intellij.psi.PsiElement; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.psi.util.PsiUtilCore; /** * @author Dennis.Ushakov @@ -66,7 +67,7 @@ public abstract class MemberInfoBase { } public T getMember() { - LOG.assertTrue(myMember.isValid(), myMember.getText() + " is invalid"); + PsiUtilCore.ensureValid(myMember); return myMember; } From 3b0cc0de47dbf5e525f06c84414c5eda3d3f3c09 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 12 Nov 2014 17:23:28 +0300 Subject: [PATCH 32/34] PY-7376 Resolving of relative imports takes into account namespace packages --- .../python/psi/resolve/ResolveImportUtil.java | 2 +- .../nspkg1/a.after.py | 1 + .../nspkg1/a.py | 1 + .../nspkg1/nspkg2/bar.py | 0 .../nspkg1/nspkg2/foo.py | 0 .../nspkg1/a.after.py | 1 + .../nspkg1/a.py | 1 + .../nspkg1/bar.py | 0 .../nspkg1/foo.py | 0 .../com/jetbrains/python/Py3CompletionTest.java | 17 +++++++++++++++++ 10 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 python/testData/completion/relativeFromImportInNamespacePackage/nspkg1/a.after.py create mode 100644 python/testData/completion/relativeFromImportInNamespacePackage/nspkg1/a.py create mode 100644 python/testData/completion/relativeFromImportInNamespacePackage/nspkg1/nspkg2/bar.py create mode 100644 python/testData/completion/relativeFromImportInNamespacePackage/nspkg1/nspkg2/foo.py create mode 100644 python/testData/completion/relativeFromImportInNamespacePackage2/nspkg1/a.after.py create mode 100644 python/testData/completion/relativeFromImportInNamespacePackage2/nspkg1/a.py create mode 100644 python/testData/completion/relativeFromImportInNamespacePackage2/nspkg1/bar.py create mode 100644 python/testData/completion/relativeFromImportInNamespacePackage2/nspkg1/foo.py diff --git a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java index 1f6d9d5f893b..e2ea4a797317 100644 --- a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java +++ b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java @@ -95,7 +95,7 @@ public class ResolveImportUtil { base = base.getOriginalFile(); // just to make sure result = base.getContainingDirectory(); int count = 1; - while (result != null && result.findFile(PyNames.INIT_DOT_PY) != null) { + while (result != null && PyUtil.isPackage(result, base)) { if (count >= depth) return result; result = result.getParentDirectory(); count += 1; diff --git a/python/testData/completion/relativeFromImportInNamespacePackage/nspkg1/a.after.py b/python/testData/completion/relativeFromImportInNamespacePackage/nspkg1/a.after.py new file mode 100644 index 000000000000..c36bd9b160b9 --- /dev/null +++ b/python/testData/completion/relativeFromImportInNamespacePackage/nspkg1/a.after.py @@ -0,0 +1 @@ +from .nspkg2 import foo \ No newline at end of file diff --git a/python/testData/completion/relativeFromImportInNamespacePackage/nspkg1/a.py b/python/testData/completion/relativeFromImportInNamespacePackage/nspkg1/a.py new file mode 100644 index 000000000000..59cec1ed8401 --- /dev/null +++ b/python/testData/completion/relativeFromImportInNamespacePackage/nspkg1/a.py @@ -0,0 +1 @@ +from .nspkg2 import f \ No newline at end of file diff --git a/python/testData/completion/relativeFromImportInNamespacePackage/nspkg1/nspkg2/bar.py b/python/testData/completion/relativeFromImportInNamespacePackage/nspkg1/nspkg2/bar.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/relativeFromImportInNamespacePackage/nspkg1/nspkg2/foo.py b/python/testData/completion/relativeFromImportInNamespacePackage/nspkg1/nspkg2/foo.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/relativeFromImportInNamespacePackage2/nspkg1/a.after.py b/python/testData/completion/relativeFromImportInNamespacePackage2/nspkg1/a.after.py new file mode 100644 index 000000000000..b3dc38201dc4 --- /dev/null +++ b/python/testData/completion/relativeFromImportInNamespacePackage2/nspkg1/a.after.py @@ -0,0 +1 @@ +from . import foo \ No newline at end of file diff --git a/python/testData/completion/relativeFromImportInNamespacePackage2/nspkg1/a.py b/python/testData/completion/relativeFromImportInNamespacePackage2/nspkg1/a.py new file mode 100644 index 000000000000..f9d269cb07e8 --- /dev/null +++ b/python/testData/completion/relativeFromImportInNamespacePackage2/nspkg1/a.py @@ -0,0 +1 @@ +from . import f \ No newline at end of file diff --git a/python/testData/completion/relativeFromImportInNamespacePackage2/nspkg1/bar.py b/python/testData/completion/relativeFromImportInNamespacePackage2/nspkg1/bar.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/relativeFromImportInNamespacePackage2/nspkg1/foo.py b/python/testData/completion/relativeFromImportInNamespacePackage2/nspkg1/foo.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testSrc/com/jetbrains/python/Py3CompletionTest.java b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java index 5fe31bdedeb3..7e085a397a2e 100644 --- a/python/testSrc/com/jetbrains/python/Py3CompletionTest.java +++ b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java @@ -119,4 +119,21 @@ public class Py3CompletionTest extends PyTestCase { public void testImportNestedQualifiedNamespacePackage() { doMultiFileTest(); } + + // PY-7376 + public void testRelativeFromImportInNamespacePackage() { + doMultiFileTestInsideNamespacePackage(); + } + + // PY-7376 + public void testRelativeFromImportInNamespacePackage2() { + doMultiFileTestInsideNamespacePackage(); + } + + private void doMultiFileTestInsideNamespacePackage() { + myFixture.copyDirectoryToProject("completion/" + getTestName(true), ""); + myFixture.configureByFile("nspkg1/a.py"); + myFixture.completeBasic(); + myFixture.checkResultByFile("completion/" + getTestName(true) + "/nspkg1/a.after.py"); + } } From dcd1bd2a91c497f5d1a2ae299ecd91ac45436267 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 12 Nov 2014 20:28:26 +0300 Subject: [PATCH 33/34] PY-7378 Add test cases described in issue (problem has been fixed already) --- .../moveNamespacePackageTest1/after/src/b.py | 3 ++ .../after/src/nssubpkg/__init__.py | 1 + .../after/src/nssubpkg/a.py | 1 + .../moveNamespacePackageTest1/before/src/b.py | 3 ++ .../before/src/nspkg/nssubpkg/a.py | 1 + .../moveNamespacePackageTest2/after/src/a.py | 1 + .../moveNamespacePackageTest2/after/src/b.py | 3 ++ .../moveNamespacePackageTest2/before/src/b.py | 3 ++ .../before/src/nspkg/nssubpkg/a.py | 1 + .../moveNamespacePackageTest3/after/src/b.py | 3 ++ .../after/src/nspkg/__init__.py | 1 + .../after/src/nspkg/a.py | 1 + .../moveNamespacePackageTest3/before/src/b.py | 3 ++ .../before/src/nspkg/nssubpkg/a.py | 1 + .../python/PyMultiFileResolveTest.java | 3 +- .../python/refactoring/PyMoveTest.java | 32 +++++++++++++++++++ 16 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 python/testData/refactoring/move/moveNamespacePackageTest1/after/src/b.py create mode 100644 python/testData/refactoring/move/moveNamespacePackageTest1/after/src/nssubpkg/__init__.py create mode 100644 python/testData/refactoring/move/moveNamespacePackageTest1/after/src/nssubpkg/a.py create mode 100644 python/testData/refactoring/move/moveNamespacePackageTest1/before/src/b.py create mode 100644 python/testData/refactoring/move/moveNamespacePackageTest1/before/src/nspkg/nssubpkg/a.py create mode 100644 python/testData/refactoring/move/moveNamespacePackageTest2/after/src/a.py create mode 100644 python/testData/refactoring/move/moveNamespacePackageTest2/after/src/b.py create mode 100644 python/testData/refactoring/move/moveNamespacePackageTest2/before/src/b.py create mode 100644 python/testData/refactoring/move/moveNamespacePackageTest2/before/src/nspkg/nssubpkg/a.py create mode 100644 python/testData/refactoring/move/moveNamespacePackageTest3/after/src/b.py create mode 100644 python/testData/refactoring/move/moveNamespacePackageTest3/after/src/nspkg/__init__.py create mode 100644 python/testData/refactoring/move/moveNamespacePackageTest3/after/src/nspkg/a.py create mode 100644 python/testData/refactoring/move/moveNamespacePackageTest3/before/src/b.py create mode 100644 python/testData/refactoring/move/moveNamespacePackageTest3/before/src/nspkg/nssubpkg/a.py diff --git a/python/testData/refactoring/move/moveNamespacePackageTest1/after/src/b.py b/python/testData/refactoring/move/moveNamespacePackageTest1/after/src/b.py new file mode 100644 index 000000000000..f6d076221811 --- /dev/null +++ b/python/testData/refactoring/move/moveNamespacePackageTest1/after/src/b.py @@ -0,0 +1,3 @@ +import nssubpkg.a + +print(nssubpkg.a.VAR) \ No newline at end of file diff --git a/python/testData/refactoring/move/moveNamespacePackageTest1/after/src/nssubpkg/__init__.py b/python/testData/refactoring/move/moveNamespacePackageTest1/after/src/nssubpkg/__init__.py new file mode 100644 index 000000000000..09ee69e66c3c --- /dev/null +++ b/python/testData/refactoring/move/moveNamespacePackageTest1/after/src/nssubpkg/__init__.py @@ -0,0 +1 @@ +__author__ = 'user1' diff --git a/python/testData/refactoring/move/moveNamespacePackageTest1/after/src/nssubpkg/a.py b/python/testData/refactoring/move/moveNamespacePackageTest1/after/src/nssubpkg/a.py new file mode 100644 index 000000000000..fe5433bef744 --- /dev/null +++ b/python/testData/refactoring/move/moveNamespacePackageTest1/after/src/nssubpkg/a.py @@ -0,0 +1 @@ +VAR = 42 \ No newline at end of file diff --git a/python/testData/refactoring/move/moveNamespacePackageTest1/before/src/b.py b/python/testData/refactoring/move/moveNamespacePackageTest1/before/src/b.py new file mode 100644 index 000000000000..316c5822cf5c --- /dev/null +++ b/python/testData/refactoring/move/moveNamespacePackageTest1/before/src/b.py @@ -0,0 +1,3 @@ +import nspkg.nssubpkg.a + +print(nspkg.nssubpkg.a.VAR) \ No newline at end of file diff --git a/python/testData/refactoring/move/moveNamespacePackageTest1/before/src/nspkg/nssubpkg/a.py b/python/testData/refactoring/move/moveNamespacePackageTest1/before/src/nspkg/nssubpkg/a.py new file mode 100644 index 000000000000..fe5433bef744 --- /dev/null +++ b/python/testData/refactoring/move/moveNamespacePackageTest1/before/src/nspkg/nssubpkg/a.py @@ -0,0 +1 @@ +VAR = 42 \ No newline at end of file diff --git a/python/testData/refactoring/move/moveNamespacePackageTest2/after/src/a.py b/python/testData/refactoring/move/moveNamespacePackageTest2/after/src/a.py new file mode 100644 index 000000000000..fe5433bef744 --- /dev/null +++ b/python/testData/refactoring/move/moveNamespacePackageTest2/after/src/a.py @@ -0,0 +1 @@ +VAR = 42 \ No newline at end of file diff --git a/python/testData/refactoring/move/moveNamespacePackageTest2/after/src/b.py b/python/testData/refactoring/move/moveNamespacePackageTest2/after/src/b.py new file mode 100644 index 000000000000..fef2db61a5de --- /dev/null +++ b/python/testData/refactoring/move/moveNamespacePackageTest2/after/src/b.py @@ -0,0 +1,3 @@ +import a + +print(a.VAR) \ No newline at end of file diff --git a/python/testData/refactoring/move/moveNamespacePackageTest2/before/src/b.py b/python/testData/refactoring/move/moveNamespacePackageTest2/before/src/b.py new file mode 100644 index 000000000000..316c5822cf5c --- /dev/null +++ b/python/testData/refactoring/move/moveNamespacePackageTest2/before/src/b.py @@ -0,0 +1,3 @@ +import nspkg.nssubpkg.a + +print(nspkg.nssubpkg.a.VAR) \ No newline at end of file diff --git a/python/testData/refactoring/move/moveNamespacePackageTest2/before/src/nspkg/nssubpkg/a.py b/python/testData/refactoring/move/moveNamespacePackageTest2/before/src/nspkg/nssubpkg/a.py new file mode 100644 index 000000000000..fe5433bef744 --- /dev/null +++ b/python/testData/refactoring/move/moveNamespacePackageTest2/before/src/nspkg/nssubpkg/a.py @@ -0,0 +1 @@ +VAR = 42 \ No newline at end of file diff --git a/python/testData/refactoring/move/moveNamespacePackageTest3/after/src/b.py b/python/testData/refactoring/move/moveNamespacePackageTest3/after/src/b.py new file mode 100644 index 000000000000..46889e52b2f4 --- /dev/null +++ b/python/testData/refactoring/move/moveNamespacePackageTest3/after/src/b.py @@ -0,0 +1,3 @@ +import nspkg.a + +print(nspkg.a.VAR) \ No newline at end of file diff --git a/python/testData/refactoring/move/moveNamespacePackageTest3/after/src/nspkg/__init__.py b/python/testData/refactoring/move/moveNamespacePackageTest3/after/src/nspkg/__init__.py new file mode 100644 index 000000000000..09ee69e66c3c --- /dev/null +++ b/python/testData/refactoring/move/moveNamespacePackageTest3/after/src/nspkg/__init__.py @@ -0,0 +1 @@ +__author__ = 'user1' diff --git a/python/testData/refactoring/move/moveNamespacePackageTest3/after/src/nspkg/a.py b/python/testData/refactoring/move/moveNamespacePackageTest3/after/src/nspkg/a.py new file mode 100644 index 000000000000..fe5433bef744 --- /dev/null +++ b/python/testData/refactoring/move/moveNamespacePackageTest3/after/src/nspkg/a.py @@ -0,0 +1 @@ +VAR = 42 \ No newline at end of file diff --git a/python/testData/refactoring/move/moveNamespacePackageTest3/before/src/b.py b/python/testData/refactoring/move/moveNamespacePackageTest3/before/src/b.py new file mode 100644 index 000000000000..316c5822cf5c --- /dev/null +++ b/python/testData/refactoring/move/moveNamespacePackageTest3/before/src/b.py @@ -0,0 +1,3 @@ +import nspkg.nssubpkg.a + +print(nspkg.nssubpkg.a.VAR) \ No newline at end of file diff --git a/python/testData/refactoring/move/moveNamespacePackageTest3/before/src/nspkg/nssubpkg/a.py b/python/testData/refactoring/move/moveNamespacePackageTest3/before/src/nspkg/nssubpkg/a.py new file mode 100644 index 000000000000..fe5433bef744 --- /dev/null +++ b/python/testData/refactoring/move/moveNamespacePackageTest3/before/src/nspkg/nssubpkg/a.py @@ -0,0 +1 @@ +VAR = 42 \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java b/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java index 6073f713eb0e..244be9594dd8 100644 --- a/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java +++ b/python/testSrc/com/jetbrains/python/PyMultiFileResolveTest.java @@ -374,6 +374,7 @@ public class PyMultiFileResolveTest extends PyMultiFileResolveTestCase { assertResolvesTo(PyTargetExpression.class, "_private_name"); } + // PY-7378 public void testModuleInDeeplyNestedNamespacePackage() { runWithLanguageLevel(LanguageLevel.PYTHON33, new Runnable() { @Override @@ -382,4 +383,4 @@ public class PyMultiFileResolveTest extends PyMultiFileResolveTestCase { } }); } -} +} \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java index b6a1a1f78a88..32935d61c924 100644 --- a/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java +++ b/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java @@ -23,6 +23,7 @@ import com.intellij.testFramework.PlatformTestUtil; import com.intellij.util.SystemProperties; import com.jetbrains.python.PythonTestUtil; import com.jetbrains.python.fixtures.PyTestCase; +import com.jetbrains.python.psi.LanguageLevel; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyFunction; import com.jetbrains.python.psi.stubs.PyClassNameIndex; @@ -138,6 +139,37 @@ public class PyMoveTest extends PyTestCase { doMoveFileTest("mod2.py", "pkg1"); } + // PY-7378 + public void testMoveNamespacePackageTest1() { + runWithLanguageLevel(LanguageLevel.PYTHON33, new Runnable() { + @Override + public void run() { + doMoveFileTest("nspkg/nssubpkg", ""); + } + }); + } + + // PY-7378 + public void testMoveNamespacePackageTest2() { + runWithLanguageLevel(LanguageLevel.PYTHON33, new Runnable() { + @Override + public void run() { + doMoveFileTest("nspkg/nssubpkg/a.py", ""); + } + }); + } + + // PY-7378 + public void testMoveNamespacePackageTest3() { + runWithLanguageLevel(LanguageLevel.PYTHON33, new Runnable() { + @Override + public void run() { + doMoveFileTest("nspkg/nssubpkg/a.py", "nspkg"); + } + }); + } + + private void doMoveFileTest(String fileName, String toDirName) { Project project = myFixture.getProject(); PsiManager manager = PsiManager.getInstance(project); From dafd870b859767e51a5443fbe5e09197f486a0f2 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 12 Nov 2014 20:59:36 +0300 Subject: [PATCH 34/34] Do not create __init__.py when moving namespace packages --- .../refactoring/move/PyMoveFileHandler.java | 18 ++++++++++++++++-- .../after/src/nssubpkg/__init__.py | 1 - .../after/src/nspkg/__init__.py | 1 - 3 files changed, 16 insertions(+), 4 deletions(-) delete mode 100644 python/testData/refactoring/move/moveNamespacePackageTest1/after/src/nssubpkg/__init__.py delete mode 100644 python/testData/refactoring/move/moveNamespacePackageTest3/after/src/nspkg/__init__.py diff --git a/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java b/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java index 0c9efef01200..7044a978438d 100644 --- a/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java +++ b/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java @@ -23,15 +23,16 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiNamedElement; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.QualifiedName; import com.intellij.refactoring.RefactoringSettings; import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFileHandler; import com.intellij.usageView.UsageInfo; import com.intellij.util.IncorrectOperationException; +import com.jetbrains.python.PyNames; import com.jetbrains.python.PythonFileType; import com.jetbrains.python.actions.CreatePackageAction; import com.jetbrains.python.codeInsight.imports.PyImportOptimizer; import com.jetbrains.python.psi.*; -import com.intellij.psi.util.QualifiedName; import com.jetbrains.python.psi.resolve.QualifiedNameFinder; import com.jetbrains.python.refactoring.PyRefactoringUtil; import com.jetbrains.python.refactoring.classes.PyClassRefactoringUtil; @@ -64,13 +65,26 @@ public class PyMoveFileHandler extends MoveFileHandler { root = root.getParentDirectory(); } final boolean searchForReferences = RefactoringSettings.getInstance().MOVE_SEARCH_FOR_REFERENCES_FOR_FILE; - if (moveDestination != root && root != null && searchForReferences) { + if (moveDestination != root && root != null && searchForReferences && !probablyNamespacePackage(file, moveDestination, root)) { CreatePackageAction.createInitPyInHierarchy(moveDestination, root); } } // TODO: Update relative imports } + private static boolean probablyNamespacePackage(@NotNull PsiFile anchor, @NotNull PsiDirectory destination, @NotNull PsiDirectory root) { + if (!LanguageLevel.forElement(anchor).isAtLeast(LanguageLevel.PYTHON33)) { + return false; + } + while (destination != null && destination != root) { + if (destination.findFile(PyNames.INIT_DOT_PY) != null) { + return false; + } + destination = destination.getParent(); + } + return true; + } + @Override public List findUsages(PsiFile file, PsiDirectory newParent, boolean searchInComments, boolean searchInNonJavaFiles) { if (file != null) { diff --git a/python/testData/refactoring/move/moveNamespacePackageTest1/after/src/nssubpkg/__init__.py b/python/testData/refactoring/move/moveNamespacePackageTest1/after/src/nssubpkg/__init__.py deleted file mode 100644 index 09ee69e66c3c..000000000000 --- a/python/testData/refactoring/move/moveNamespacePackageTest1/after/src/nssubpkg/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'user1' diff --git a/python/testData/refactoring/move/moveNamespacePackageTest3/after/src/nspkg/__init__.py b/python/testData/refactoring/move/moveNamespacePackageTest3/after/src/nspkg/__init__.py deleted file mode 100644 index 09ee69e66c3c..000000000000 --- a/python/testData/refactoring/move/moveNamespacePackageTest3/after/src/nspkg/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'user1'