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); + // } + // } + //}); } } 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-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) { 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 {}") 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/openapi/application/ex/ApplicationUtil.java b/platform/core-impl/src/com/intellij/openapi/application/ex/ApplicationUtil.java index 94061b31acee..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 @@ -23,7 +23,10 @@ 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 @@ -63,7 +66,7 @@ public class ApplicationUtil { error.set(t); return null; } - }; + } }); while (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..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 @@ -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.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) { 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 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; } 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/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) { 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 {} } 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/ide/plugins/RepositoryContentHandler.java b/platform/platform-impl/src/com/intellij/ide/plugins/RepositoryContentHandler.java index a28be60dbf9d..5629398b47e1 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. @@ -16,22 +16,17 @@ 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; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import java.util.ArrayList; -import java.util.Stack; +import java.util.List; -/** - * 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 { +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"; @@ -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; } 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 4bc51f9b2e36..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 @@ -23,18 +23,17 @@ 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; 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; @@ -42,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; @@ -89,17 +87,11 @@ public class PluginDownloader { myBuildNumber = buildNumber; } - @SuppressWarnings("UnusedDeclaration") - @Deprecated - public boolean prepareToInstall() throws IOException { - return prepareToInstall(new ProgressIndicatorBase()); + public boolean prepareToInstall(@NotNull ProgressIndicator progressIndicator) throws IOException { + return prepareToInstall(progressIndicator, myBuildNumber); } - public boolean prepareToInstall(ProgressIndicator pi) throws IOException { - return prepareToInstall(pi, 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; } @@ -176,11 +168,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); @@ -237,69 +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 { - connection = openConnection(myPluginUrl); - - final InputStream is = (ApplicationManager.getApplication() != null) - ? UrlConnectionUtil.getConnectionInputStream(connection, progressIndicator) - : connection.getInputStream(); - if (is == null) { - throw new IOException("Failed to open connection"); + return HttpRequests.request(myPluginUrl).supportGzip(false).effectiveUrlConsumer(new Consumer() { + @Override + public void consume(String url) { + myPluginUrl = url; } + }).get(new ThrowableConvertor() { + @Override + public File convert(URLConnection connection) throws IOException { + progressIndicator.checkCanceled(); - 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; } - } - } - - 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 { + 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/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 08ed9832de5c..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,13 +29,11 @@ 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; @@ -45,6 +42,7 @@ 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; @@ -55,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. @@ -130,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); } @@ -160,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; } @@ -284,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); @@ -341,52 +339,81 @@ 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(@NotNull String host, final Map downloaded, final @Nullable Collection incompatiblePlugins, - final boolean collectToUpdate, - final @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) { @@ -401,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); @@ -433,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); @@ -460,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 + "' )"); } @@ -471,12 +501,10 @@ 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 { - InputStream inputStream = connection.getInputStream(); + InputStream inputStream = HttpRequests.getInputStream(connection); try { return new UpdatesInfo(JDOMUtil.loadDocument(inputStream).getRootElement()); } @@ -501,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); } @@ -644,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); @@ -739,12 +721,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())); 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 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; + } + } +} 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/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-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()) { 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} 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 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) { 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..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 @@ -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 { @@ -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; } 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..960eb234042d 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), 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) { 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..c5bc11f485bd 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,12 @@ 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 + 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, @@ -324,7 +330,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 +410,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()) { diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java index 9264b4f0f027..2fd0374ae545 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 + "\n"); + } } } } 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/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/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/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/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/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/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"); + } } 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); 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);