diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpColorsPage.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpColorsPage.java index 8afcb738c59e..1c175c978094 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpColorsPage.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpColorsPage.java @@ -15,7 +15,6 @@ */ package org.intellij.lang.regexp; -import com.intellij.application.options.colors.InspectionColorSettingsPage; import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.openapi.fileTypes.SyntaxHighlighter; import com.intellij.openapi.options.colors.AttributesDescriptor; @@ -31,13 +30,20 @@ import java.util.Map; /** * @author traff */ -public class RegExpColorsPage implements ColorSettingsPage, InspectionColorSettingsPage { +public class RegExpColorsPage implements ColorSettingsPage { private static final AttributesDescriptor[] ATTRS = new AttributesDescriptor[] { - new AttributesDescriptor("Keywords", RegExpHighlighter.META), - new AttributesDescriptor("Escaped characters", RegExpHighlighter.ESC_CHARACTER), - new AttributesDescriptor("Braces", RegExpHighlighter.BRACES), - new AttributesDescriptor("Brackets", RegExpHighlighter.BRACKETS), + new AttributesDescriptor("Keyword", RegExpHighlighter.META), + new AttributesDescriptor("Escaped character", RegExpHighlighter.ESC_CHARACTER), + new AttributesDescriptor("Invalid escape sequence", RegExpHighlighter.INVALID_CHARACTER_ESCAPE), + new AttributesDescriptor("Redundant escape sequence", RegExpHighlighter.REDUNDANT_ESCAPE), + new AttributesDescriptor("Brace", RegExpHighlighter.BRACES), + new AttributesDescriptor("Bracket", RegExpHighlighter.BRACKETS), new AttributesDescriptor("Parenthesis", RegExpHighlighter.PARENTHS), + new AttributesDescriptor("Comma", RegExpHighlighter.COMMA), + new AttributesDescriptor("Bad character", RegExpHighlighter.BAD_CHARACTER), + new AttributesDescriptor("Character class", RegExpHighlighter.CHAR_CLASS), + new AttributesDescriptor("Quote character", RegExpHighlighter.QUOTE_CHARACTER), + new AttributesDescriptor("Comment", RegExpHighlighter.COMMENT) }; @NonNls private static final HashMap ourTagToDescriptorMap = new HashMap(); @@ -71,7 +77,7 @@ public class RegExpColorsPage implements ColorSettingsPage, InspectionColorSetti @NotNull public String getDemoText() { return - "^[\\w\\.-]+@([\\w\\-]+\\.)+[A-Z]{2,4}$"; + "^[\\w\\.-]+@([\\w\\-]+\\.)+[A-Z]{2,4}\\x0g\\#\\p{alpha}\\Q\\E$"; } diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpHighlighter.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpHighlighter.java index 141391a7cbeb..17da2ae193b4 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpHighlighter.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpHighlighter.java @@ -78,10 +78,6 @@ class RegExpHighlighter extends SyntaxHighlighterBase { "REGEXP.QUOTE_CHARACTER", SyntaxHighlighterColors.VALID_STRING_ESCAPE.getDefaultAttributes() ); - static final TextAttributesKey CTRL_CHARACTER = TextAttributesKey.createTextAttributesKey( - "REGEXP.CTRL_CHARACTER", - SyntaxHighlighterColors.VALID_STRING_ESCAPE.getDefaultAttributes() - ); static final TextAttributesKey COMMENT = TextAttributesKey.createTextAttributesKey( "REGEXP.COMMENT", SyntaxHighlighterColors.LINE_COMMENT.getDefaultAttributes() @@ -108,7 +104,6 @@ class RegExpHighlighter extends SyntaxHighlighterBase { keys1.put(RegExpTT.BAD_HEX_VALUE, INVALID_CHARACTER_ESCAPE); keys1.put(RegExpTT.BAD_OCT_VALUE, INVALID_CHARACTER_ESCAPE); - keys1.put(RegExpTT.CTRL_CHARACTER, CTRL_CHARACTER); keys1.put(RegExpTT.PROPERTY, CHAR_CLASS); keys1.put(RegExpTT.ESC_CHARACTER, ESC_CHARACTER); diff --git a/bin/win/idea.bat b/bin/win/idea.bat index 632ae9142b2d..b849c97c2729 100644 --- a/bin/win/idea.bat +++ b/bin/win/idea.bat @@ -6,7 +6,7 @@ :: --------------------------------------------------------------------- :: Before you run IntelliJ IDEA specify the location of the -:: JDK 1.5 installation directory which will be used for running IDEA +:: JDK 1.6 installation directory which will be used for running IDEA :: --------------------------------------------------------------------- IF "%IDEA_JDK%" == "" SET IDEA_JDK=%JDK_HOME% IF "%IDEA_JDK%" == "" goto error diff --git a/build/Install-Linux-tar.txt b/build/Install-Linux-tar.txt new file mode 100644 index 000000000000..d51b005ba33d --- /dev/null +++ b/build/Install-Linux-tar.txt @@ -0,0 +1,51 @@ +IntelliJ IDEA + +INSTALLATION INSTRUCTIONS +=============================================================================== + + Linux Installation Instructions + ------------------------------------------------------------------------------ + 1. Unpack the IntelliJ IDEA distribution file that you downloaded to + where you wish to install the program. We will refer to this destination + location as your {installation home} below. + + 2. Open a console and cd into "{installation home}/bin" and type: + + ./idea.sh + + to start the application. + + 3. [OPTIONAL] Add the "{installation home}/bin" to your PATH environmental + variable so that you may start IntelliJ IDEA from any directory. + + 4. [OPTIONAL] To adjust the value of JVM heap size open idea.vmoptions and + modify the -Xms and -Xmx parameters. + + + [OPTIONAL] Changing location of "config" and "system" directory + ------------------------------------------------------------------------------ + By default IDEA stores all your settings under ~/.IntelliJIdea10/config directory + and stores data cache under ~/.IntelliJIdea10/system directory. + If you want to change these settings, + + 1. Open a console and cd into "{installation home}/bin" + + 2. Open file "idea.properties" in an editor. You should find strings like + + idea.system.path=~/.IntelliJIdea10/system + + and + + idea.config.path=~/.IntelliJIdea10/config + + and change them. + + 3. Note that we recommend to store data cache ("system" directory) at a disk + with at least 1G bytes free space + + + + +Enjoy! + +-IntelliJ IDEA Development Team diff --git a/build/scripts/dist.gant b/build/scripts/dist.gant index d2635baf3b05..bd8d82c0364d 100644 --- a/build/scripts/dist.gant +++ b/build/scripts/dist.gant @@ -198,6 +198,7 @@ def layoutLinux(Map args, String home, Paths paths) { fileset(dir: "$home/bin/nix") fileset(dir: "$home/build/images") } + fileset(dir: "$home/build", includes: "Install-Linux-tar.txt") } patchPropertiesFile(paths.distUnix) diff --git a/community-resources/src/idea/IdeaApplicationInfo.xml b/community-resources/src/idea/IdeaApplicationInfo.xml index 1bcdca8d3b40..3ab6ac4dd875 100644 --- a/community-resources/src/idea/IdeaApplicationInfo.xml +++ b/community-resources/src/idea/IdeaApplicationInfo.xml @@ -18,8 +18,8 @@ - + diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleEditor.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleEditor.java index 59e25af14f35..6816f8112021 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleEditor.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleEditor.java @@ -30,6 +30,7 @@ import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.ModuleRootModel; import com.intellij.openapi.roots.OrderEntry; import com.intellij.openapi.roots.impl.ModuleRootManagerImpl; +import com.intellij.openapi.roots.impl.libraries.LibraryTableBase; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.libraries.LibraryTable; import com.intellij.openapi.util.ActionCallback; @@ -427,7 +428,7 @@ public abstract class ModuleEditor implements Place.Navigator, Disposable { new LibraryInvocationHandler((Library)result)); } else if (result instanceof LibraryTable.ModifiableModel) { - return Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{LibraryTable.ModifiableModel.class}, + return Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{LibraryTableBase.ModifiableModelEx.class}, new LibraryTableModelInvocationHandler((LibraryTable.ModifiableModel)result)); } if (result instanceof Library[]) { diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/BlockContainingJavaBlock.java b/java/java-impl/src/com/intellij/psi/formatter/java/BlockContainingJavaBlock.java index c8b11d1f9f08..b5c7822cbb01 100644 --- a/java/java-impl/src/com/intellij/psi/formatter/java/BlockContainingJavaBlock.java +++ b/java/java-impl/src/com/intellij/psi/formatter/java/BlockContainingJavaBlock.java @@ -17,12 +17,15 @@ package com.intellij.psi.formatter.java; import com.intellij.formatting.*; import com.intellij.lang.ASTNode; +import com.intellij.psi.JavaTokenType; import com.intellij.psi.codeStyle.CodeStyleSettings; import com.intellij.psi.formatter.FormatterUtil; import com.intellij.psi.impl.source.tree.ElementType; import com.intellij.psi.impl.source.tree.JavaDocElementType; +import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.impl.source.tree.StdTokenSets; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -30,6 +33,10 @@ import java.util.List; public class BlockContainingJavaBlock extends AbstractJavaBlock{ + private static final TokenSet TYPES_OF_STATEMENTS_WITH_OPTIONAL_BRACES = TokenSet.create( + JavaElementType.IF_STATEMENT, JavaElementType.WHILE_STATEMENT, JavaElementType.FOR_STATEMENT + ); + private final static int BEFORE_FIRST = 0; private final static int BEFORE_BLOCK = 1; private final static int AFTER_ELSE = 2; @@ -207,12 +214,37 @@ public class BlockContainingJavaBlock extends AbstractJavaBlock{ return new ChildAttributes(getCodeBlockExternalIndent(), null); } + boolean useExternalIndent = false; if (newChildIndex == getSubBlocks().size()) { + useExternalIndent = true; + } + else if (TYPES_OF_STATEMENTS_WITH_OPTIONAL_BRACES.contains(myNode.getElementType())) { + // There is a possible case that we have situation like below: + // if (true) + // + // System.out.println(); + // We would like to indent current caret position then because there is a high probability that the user starts + // typing there (populating statement body). So, we perform dedicated check for that here and use 'external indent' + // if necessary. + Block prevBlock = getSubBlocks().get(newChildIndex - 1); + Block nextBlock = getSubBlocks().get(newChildIndex); + if (prevBlock instanceof ASTBlock && nextBlock instanceof ASTBlock) { + ASTNode prevNode = ((ASTBlock)prevBlock).getNode(); + ASTNode nextNode = ((ASTBlock)nextBlock).getNode(); + if (prevNode != null && nextNode != null && prevNode.getElementType() == JavaTokenType.RPARENTH + && nextNode.getElementType() != JavaTokenType.LBRACE) + { + useExternalIndent = true; + } + } + } + + if (useExternalIndent) { return new ChildAttributes(getCodeBlockChildExternalIndent(newChildIndex), null); } - - return new ChildAttributes(myIndentsBefore.get(newChildIndex), null); - + else { + return new ChildAttributes(myIndentsBefore.get(newChildIndex), null); + } } private boolean isInsideForParens(final int newChildIndex) { diff --git a/java/java-impl/src/com/intellij/unscramble/UnscrambleListener.java b/java/java-impl/src/com/intellij/unscramble/UnscrambleListener.java index 120e3d83c4ef..6c44fad99e3a 100644 --- a/java/java-impl/src/com/intellij/unscramble/UnscrambleListener.java +++ b/java/java-impl/src/com/intellij/unscramble/UnscrambleListener.java @@ -16,6 +16,7 @@ package com.intellij.unscramble; import com.intellij.openapi.application.ApplicationAdapter; +import com.intellij.openapi.project.Project; import com.intellij.openapi.wm.IdeFrame; import java.util.regex.Pattern; @@ -32,8 +33,9 @@ public class UnscrambleListener extends ApplicationAdapter { final String clipboard = AnalyzeStacktraceUtil.getTextInClipboard(); if (clipboard != null && clipboard.length() < MAX_STACKTRACE_SIZE && !clipboard.equals(stacktrace)) { stacktrace = clipboard; - if (isStacktrace(stacktrace)) { - final UnscrambleDialog dialog = new UnscrambleDialog(ideFrame.getProject()); + final Project project = ideFrame.getProject(); + if (project != null && isStacktrace(stacktrace)) { + final UnscrambleDialog dialog = new UnscrambleDialog(project); dialog.createNormalizeTextAction().actionPerformed(null); dialog.doOKAction(); } diff --git a/java/java-runtime/src/com/intellij/rt/execution/junit/segments/OutputObjectRegistry.java b/java/java-runtime/src/com/intellij/rt/execution/junit/segments/OutputObjectRegistry.java index c23c9c520ee4..8b7132d6bd37 100644 --- a/java/java-runtime/src/com/intellij/rt/execution/junit/segments/OutputObjectRegistry.java +++ b/java/java-runtime/src/com/intellij/rt/execution/junit/segments/OutputObjectRegistry.java @@ -15,29 +15,42 @@ */ package com.intellij.rt.execution.junit.segments; +import java.util.Collection; import java.util.Hashtable; public abstract class OutputObjectRegistry { private final Hashtable myKnownKeys = new Hashtable(); private int myLastIndex = 0; private PacketProcessor myMainTransport; - private PacketProcessor myAuxilaryTransport; public OutputObjectRegistry(PacketProcessor transport) { myMainTransport = transport; } - public OutputObjectRegistry(PacketProcessor mainTransport, PacketProcessor auxilaryTransport) { - this(mainTransport); - myAuxilaryTransport = auxilaryTransport; - } - public String referenceTo(Object test) { if (myKnownKeys.containsKey(test)) return (String) myKnownKeys.get(test); return sendObject(test); } + public String referenceTo(Object test, Collection packets) { + if (myKnownKeys.containsKey(test)) + return (String) myKnownKeys.get(test); + return sendObject(test, packets); + } + + private String sendObject(Object test, Collection packets) { + String key = String.valueOf(myLastIndex++); + myKnownKeys.put(test, key); + final Packet packet = createPacket(); + packet.addString(PoolOfDelimiters.OBJECT_PREFIX).addReference(key); + addStringRepresentation(test, packet); + packet.addLong(getTestCont(test)); + packet.addString(PoolOfDelimiters.REFERENCE_END_STR); + packets.add(packet); + return key; + } + public Packet createPacket() { return new Packet(myMainTransport, this); } @@ -48,21 +61,13 @@ public abstract class OutputObjectRegistry { Packet packet = createPacket().addString(PoolOfDelimiters.OBJECT_PREFIX).addReference(key); addStringRepresentation(test, packet); packet.addLong(getTestCont(test)); - sendViaAllTransports(packet); + packet.send(); return key; } protected abstract int getTestCont(Object test); protected abstract void addStringRepresentation(Object test, Packet packet); - private void sendViaAllTransports(Packet packet) { - packet.send(); - if (myAuxilaryTransport != null) - packet.sendThrough(myAuxilaryTransport); - } - - - protected static void addTestClass(Packet packet, String className) { packet. addLimitedString(PoolOfTestTypes.TEST_CLASS). diff --git a/java/java-runtime/src/com/intellij/rt/execution/junit/segments/Packet.java b/java/java-runtime/src/com/intellij/rt/execution/junit/segments/Packet.java index b1970a947b6f..8e72223bfa35 100644 --- a/java/java-runtime/src/com/intellij/rt/execution/junit/segments/Packet.java +++ b/java/java-runtime/src/com/intellij/rt/execution/junit/segments/Packet.java @@ -18,6 +18,7 @@ package com.intellij.rt.execution.junit.segments; import junit.runner.BaseTestRunner; import java.io.*; +import java.util.Collection; import java.util.Vector; public class Packet extends PacketWriter { @@ -36,6 +37,10 @@ public class Packet extends PacketWriter { return addReference(myRegistry.referenceTo(test)); } + public Packet addObject(Object test, Collection packet) { + return addReference(myRegistry.referenceTo(test, packet)); + } + public Packet addReference(String reference) { appendString(reference + PoolOfDelimiters.REFERENCE_END); return this; diff --git a/java/java-runtime/src/com/intellij/rt/execution/junit/segments/PoolOfDelimiters.java b/java/java-runtime/src/com/intellij/rt/execution/junit/segments/PoolOfDelimiters.java index 21f115f1038f..6f87e8c788b1 100644 --- a/java/java-runtime/src/com/intellij/rt/execution/junit/segments/PoolOfDelimiters.java +++ b/java/java-runtime/src/com/intellij/rt/execution/junit/segments/PoolOfDelimiters.java @@ -20,6 +20,7 @@ package com.intellij.rt.execution.junit.segments; */ public interface PoolOfDelimiters { char REFERENCE_END = ':'; + String REFERENCE_END_STR = ":"; char INTEGER_DELIMITER = ' '; String OBJECT_PREFIX = "O"; diff --git a/java/testFramework/src/com/intellij/codeInsight/CodeInsightTestCase.java b/java/testFramework/src/com/intellij/codeInsight/CodeInsightTestCase.java index 4cbcebdc186a..6028e2bfb1c3 100644 --- a/java/testFramework/src/com/intellij/codeInsight/CodeInsightTestCase.java +++ b/java/testFramework/src/com/intellij/codeInsight/CodeInsightTestCase.java @@ -240,8 +240,7 @@ public abstract class CodeInsightTestCase extends PsiTestCase { } })); - // grand VFS refresh significantly slows down local tests and generally not needed - //VirtualFileManager.getInstance().refresh(false); + toDir.refresh(false, true); } else { editorInfos = new LinkedHashMap(); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiElementListNavigator.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiElementListNavigator.java index 7e147ae691c6..ac32823613be 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiElementListNavigator.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PsiElementListNavigator.java @@ -18,11 +18,14 @@ package com.intellij.codeInsight.daemon.impl; import com.intellij.ide.util.PsiElementListCellRenderer; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.PopupChooserBuilder; import com.intellij.psi.NavigatablePsiElement; import com.intellij.psi.PsiElement; import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.components.JBList; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.event.MouseEvent; @@ -34,35 +37,44 @@ public class PsiElementListNavigator { } public static void openTargets(MouseEvent e, NavigatablePsiElement[] targets, String title, ListCellRenderer listRenderer) { - if (targets.length == 0) return; - if (targets.length == 1){ + JBPopup popup = navigateOrCreatePopup(targets, title, listRenderer); + if (popup != null) popup.show(new RelativePoint(e)); + } + + public static void openTargets(Editor e, NavigatablePsiElement[] targets, String title, ListCellRenderer listRenderer) { + JBPopup popup = navigateOrCreatePopup(targets, title, listRenderer); + if (popup != null) popup.showInBestPositionFor(e); + } + + @Nullable + private static JBPopup navigateOrCreatePopup(NavigatablePsiElement[] targets, String title, ListCellRenderer listRenderer) { + if (targets.length == 0) return null; + if (targets.length == 1) { targets[0].navigate(true); + return null; } - else{ - final JList list = new JBList(targets); - list.setCellRenderer(listRenderer); + final JList list = new JBList(targets); + list.setCellRenderer(listRenderer); - final PopupChooserBuilder builder = new PopupChooserBuilder(list); - if (listRenderer instanceof PsiElementListCellRenderer) { - ((PsiElementListCellRenderer)listRenderer).installSpeedSearch(builder); - } + final PopupChooserBuilder builder = new PopupChooserBuilder(list); + if (listRenderer instanceof PsiElementListCellRenderer) { + ((PsiElementListCellRenderer)listRenderer).installSpeedSearch(builder); + } - builder. - setTitle(title). - setMovable(true). - setItemChoosenCallback(new Runnable() { - public void run() { - int[] ids = list.getSelectedIndices(); - if (ids == null || ids.length == 0) return; - Object [] selectedElements = list.getSelectedValues(); - for (Object element : selectedElements) { - PsiElement selected = (PsiElement) element; - LOG.assertTrue(selected.isValid()); - ((NavigatablePsiElement)selected).navigate(true); - } + return builder. + setTitle(title). + setMovable(true). + setItemChoosenCallback(new Runnable() { + public void run() { + int[] ids = list.getSelectedIndices(); + if (ids == null || ids.length == 0) return; + Object[] selectedElements = list.getSelectedValues(); + for (Object element : selectedElements) { + PsiElement selected = (PsiElement)element; + LOG.assertTrue(selected.isValid()); + ((NavigatablePsiElement)selected).navigate(true); } - }).createPopup(). - show(new RelativePoint(e)); - } + } + }).createPopup(); } } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java index e08c4a7d677e..0bc22bbeea7c 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java @@ -1668,11 +1668,28 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo nextAction.getTemplatePresentation().setText(getNextOccurenceActionName()); final AnAction switchSoftWrapsAction = new ToggleUseSoftWrapsToolbarAction(SoftWrapAppliancePlaces.CONSOLE) { + + /** + * There is a possible case that more than console is open and user toggles soft wraps mode at one of them. We want + * to update another console(s) representation as well when they are switched on after that. Hence, we remember last + * used soft wraps mode and perform update if we see that the current value differs from the stored. + */ + private boolean myLastIsSelected; + @Override protected Editor getEditor(AnActionEvent e) { return myEditor; } + @Override + public boolean isSelected(AnActionEvent e) { + boolean result = super.isSelected(e); + if (result ^ myLastIsSelected) { + setSelected(null, result); + } + return myLastIsSelected = result; + } + @Override public void setSelected(AnActionEvent e, final boolean state) { super.setSelected(e, state); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReferenceSet.java b/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReferenceSet.java index 6de47a442bf5..af780a7e4535 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReferenceSet.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/providers/FileReferenceSet.java @@ -139,8 +139,7 @@ public class FileReferenceSet { public FileReferenceSet(final @NotNull PsiElement element) { myElement = element; - final ElementManipulator manipulator = ElementManipulators.getManipulator(element); - final TextRange range = manipulator.getRangeInElement(element); + TextRange range = ElementManipulators.getValueTextRange(element); myStartInElement = range.getStartOffset(); final String s = range.substring(element.getText()); myPathString = s.trim(); diff --git a/platform/lang-impl/src/com/intellij/util/ui/classpath/ChooseLibrariesDialogBase.java b/platform/lang-impl/src/com/intellij/util/ui/classpath/ChooseLibrariesDialogBase.java index cd06228cc62b..ad5ab6fdfc0e 100644 --- a/platform/lang-impl/src/com/intellij/util/ui/classpath/ChooseLibrariesDialogBase.java +++ b/platform/lang-impl/src/com/intellij/util/ui/classpath/ChooseLibrariesDialogBase.java @@ -173,7 +173,7 @@ public abstract class ChooseLibrariesDialogBase extends DialogWrapper { myTree.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "ENTER"); myTree.getActionMap().put("ENTER", getOKAction()); final JScrollPane pane = ScrollPaneFactory.createScrollPane(myTree); - pane.setMinimumSize(new Dimension(300, 80)); + pane.setPreferredSize(new Dimension(300, 80)); return pane; } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java index 1e1f076c5044..6c6da2a5a619 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceManager.java @@ -249,9 +249,14 @@ public class SoftWrapApplianceManager implements FoldingListener, DocumentListen myContext.logicalLineData.update(foldRegion.getStartOffset()); SoftWrap softWrap = registerSoftWrap( - myContext.softWrapStartOffset, myContext.tokenStartOffset, myContext.tokenStartOffset, myContext.getSpaceWidth(), myContext.logicalLineData + myContext.softWrapStartOffset, myContext.tokenStartOffset, myContext.tokenStartOffset, myContext.getSpaceWidth(), + myContext.logicalLineData ); - assert softWrap != null; // We expect that it's always possible to wrap collapsed fold region placeholder text + if (softWrap == null) { + // If we're here that means that we can't find appropriate soft wrap offset before the fold region. + // However, we expect that it's always possible to wrap collapsed fold region placeholder text + softWrap = registerSoftWrap(myContext.tokenStartOffset, myContext.getSpaceWidth(), myContext.logicalLineData); + } myContext.softWrapStartOffset = softWrap.getStart(); if (softWrap.getStart() < myContext.tokenStartOffset) { revertListeners(softWrap.getStart(), myContext.currentPosition.visualLine); @@ -524,19 +529,24 @@ public class SoftWrapApplianceManager implements FoldingListener, DocumentListen return null; } + return registerSoftWrap(softWrapOffset, spaceSize, lineData); + } + + @NotNull + private SoftWrap registerSoftWrap(int offset, int spaceSize, LogicalLineData lineData) { int indentInColumns = 0; int indentInPixels = myPainter.getMinDrawingWidth(SoftWrapDrawingType.AFTER_SOFT_WRAP); if (myCustomIndentUsedLastTime) { indentInColumns = myCustomIndentValueUsedLastTime + lineData.indentInColumns; indentInPixels += lineData.indentInPixels + (myCustomIndentValueUsedLastTime * spaceSize); } - SoftWrapImpl softWrap = new SoftWrapImpl( - new TextChangeImpl("\n" + StringUtil.repeatSymbol(' ', indentInColumns), softWrapOffset, softWrapOffset), + SoftWrapImpl result = new SoftWrapImpl( + new TextChangeImpl("\n" + StringUtil.repeatSymbol(' ', indentInColumns), offset, offset), indentInColumns + 1/* for 'after soft wrap' drawing */, indentInPixels ); - myStorage.storeOrReplace(softWrap, true); - return softWrap; + myStorage.storeOrReplace(result, true); + return result; } /** diff --git a/platform/platform-impl/src/com/intellij/util/io/ByteBufferIntObjectMap.java b/platform/platform-impl/src/com/intellij/util/io/ByteBufferIntObjectMap.java deleted file mode 100644 index 1b5a16bf6f82..000000000000 --- a/platform/platform-impl/src/com/intellij/util/io/ByteBufferIntObjectMap.java +++ /dev/null @@ -1,147 +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.util.io; - -import com.intellij.openapi.diagnostic.Logger; -import gnu.trove.TIntArrayList; -import org.jetbrains.annotations.NotNull; - -import java.io.IOException; - -public class ByteBufferIntObjectMap { - private static final Logger LOG = Logger.getInstance("#com.intellij.util.io.ByteBufferMap"); - - private final RandomAccessDataInput myBuffer; - private final int myStartOffset; - private final ByteBufferMap.ValueProvider myValueProvider; - private int myMod; - private final int myEndOffset; - - public ByteBufferIntObjectMap(@NotNull MappedBufferWrapper buffer, - int startOffset, - int endOffset, - @NotNull ByteBufferMap.ValueProvider valueProvider) { - assert startOffset < endOffset; - - myBuffer = new ByteBufferRADataInput(buffer); - myStartOffset = startOffset; - myEndOffset = endOffset; - myValueProvider = valueProvider; - - myBuffer.setPosition(startOffset); - try { - myMod = myBuffer.readInt(); - } - catch (IOException e) { - LOG.error(e); - } - } - - public V get(int key) { - int hash = hash(key); - int keyGroupOffset = readKeyGroupOffset(hash); - if (keyGroupOffset == -1) return null; - if (!(myStartOffset < keyGroupOffset && keyGroupOffset < myEndOffset)){ - LOG.error("keyGroupOffset = " + keyGroupOffset + " myStartOffset = " + myStartOffset + " myEndOffset = " + myEndOffset); - } - - try { - myBuffer.setPosition(keyGroupOffset); - int keyGroupSize = myBuffer.readInt(); - assert (keyGroupSize > 0); - for (int i = 0; i < keyGroupSize; i++) { - if (key == myBuffer.readInt()) { - int valueOffset = myBuffer.readInt(); - assert (valueOffset > 0); - - myBuffer.setPosition(myStartOffset + valueOffset); - return myValueProvider.get(myBuffer); - } - else { - myBuffer.readInt(); //read offset; - } - } - } - catch (IOException e) { - LOG.error(e); - } - - return null; - } - - public TIntArrayList getKeys() { - TIntArrayList result = new TIntArrayList(); - getKeys(result); - return result; - } - - public void getKeys(TIntArrayList dst) { - try { - myBuffer.setPosition(myStartOffset + 4 /* mod */); - - int firstKeyGroupOffset = -1; - int lastKeyGroupOffset = -1; - for (int i = 0; i < myMod; i++) { - int value = myBuffer.readInt(); - if (value != -1) { - int offset = value + myStartOffset; - if (firstKeyGroupOffset == -1) firstKeyGroupOffset = offset; - lastKeyGroupOffset = offset; - } - } - if (firstKeyGroupOffset == -1) { - return; - } - assert (firstKeyGroupOffset > myStartOffset); - assert (lastKeyGroupOffset > myStartOffset); - assert (lastKeyGroupOffset >= firstKeyGroupOffset); - - int firstValueOffset = -1; - - myBuffer.setPosition(firstKeyGroupOffset); - while (myBuffer.getPosition() <= lastKeyGroupOffset) { - int groupSize = myBuffer.readInt(); - for (int i = 0; i < groupSize; i++) { - dst.add(myBuffer.readInt()); - - int valueOffset = myBuffer.readInt(); /* value offset */ - if( firstValueOffset == -1 ) firstValueOffset = valueOffset + myStartOffset; - } - } - assert myBuffer.getPosition() == firstValueOffset; - } - catch (IOException e) { - LOG.error(e); - } - } - - private int readKeyGroupOffset(int hash) { - myBuffer.setPosition(myStartOffset + 4 /* mod */ + 4 * hash); - int offset = -1; - try { - offset = myBuffer.readInt(); - } - catch (IOException e) { - LOG.error(e); - } - if (offset == -1) return -1; - return offset + myStartOffset; - } - - private int hash(int hashCode) { - return Math.abs(hashCode) % myMod; - } -} diff --git a/platform/platform-impl/src/com/intellij/util/io/ByteBufferMap.java b/platform/platform-impl/src/com/intellij/util/io/ByteBufferMap.java deleted file mode 100644 index 1068e8d78c85..000000000000 --- a/platform/platform-impl/src/com/intellij/util/io/ByteBufferMap.java +++ /dev/null @@ -1,199 +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.util.io; - -import com.intellij.openapi.diagnostic.Logger; -import org.jetbrains.annotations.NotNull; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Collection; - -public class ByteBufferMap { - private static final Logger LOG = Logger.getInstance("#com.intellij.util.io.ByteBufferMap"); - - private final RandomAccessDataInput myBuffer; - private final int myStartOffset; - private final KeyProvider myKeyProvider; - private final ValueProvider myValueProvider; - private int myMod; - private final int myEndOffset; - - public static interface KeyProvider { - int hashCode(K key); - - void write(DataOutput out, K key) throws IOException; - - int length(K key); - - K get(DataInput in) throws IOException; - - /** - * Should move the buffer pointer to the key end. - */ - boolean equals(DataInput in, K key) throws IOException; - } - - public static interface ValueProvider { - void write(DataOutput out, V value) throws IOException; - - int length(V value); - - V get(DataInput in) throws IOException; - } - - public static void writeMap(DataOutput stream, - ValueProvider valueProvider, - WriteableMap map, - double searchFactor) throws IOException { - new ByteBufferMapWriteHandler(stream, valueProvider, map, searchFactor).execute(); - } - - public static int calcMapLength(ValueProvider valueProvider, - WriteableMap map, - double searchFactor) throws IOException { - return new ByteBufferMapWriteHandler(null, valueProvider, map, searchFactor).calcLength(); - } - - public ByteBufferMap(@NotNull MappedBufferWrapper holder, - int startOffset, - int endOffset, - @NotNull KeyProvider keyProvider, - @NotNull ValueProvider valueProvider) { - this(new ByteBufferRADataInput(holder), startOffset, endOffset, keyProvider, valueProvider); - } - - public ByteBufferMap(@NotNull RandomAccessDataInput buffer, - int startOffset, - int endOffset, - @NotNull KeyProvider keyProvider, - @NotNull ValueProvider valueProvider) { - assert startOffset < endOffset; - - myBuffer = buffer; - myStartOffset = startOffset; - myEndOffset = endOffset; - myKeyProvider = keyProvider; - myValueProvider = valueProvider; - - buffer.setPosition(startOffset); - try { - myMod = buffer.readInt(); - } - catch (IOException e) { - LOG.error(e); - } - } - - public V get(K key) { - int hash = hash(myKeyProvider.hashCode(key)); - int keyGroupOffset = readKeyGroupOffset(hash); - if (keyGroupOffset == -1) return null; - if (!(myStartOffset < keyGroupOffset && keyGroupOffset < myEndOffset)){ - LOG.error("keyGroupOffset = " + keyGroupOffset + " myStartOffset = " + myStartOffset + " myEndOffset = " + myEndOffset); - } - - try { - myBuffer.setPosition(keyGroupOffset); - int keyGroupSize = myBuffer.readInt(); - assert (keyGroupSize > 0); - for (int i = 0; i < keyGroupSize; i++) { - if (myKeyProvider.equals(myBuffer, key)) { - int valueOffset = myBuffer.readInt(); - assert (valueOffset > 0); - - myBuffer.setPosition(myStartOffset + valueOffset); - return myValueProvider.get(myBuffer); - } - else { - myBuffer.readInt(); //read offset; - } - } - } - catch (IOException e) { - LOG.error(e); - } - - return null; - } - - @SuppressWarnings({"unchecked"}) - public K[] getKeys(Class keyClass) { - ArrayList result = new ArrayList(); - getKeys(keyClass, result); - return result.toArray((K[])Array.newInstance(keyClass, result.size())); - } - - public void getKeys(Class keyClass, Collection dst) { - try { - myBuffer.setPosition(myStartOffset + 4 /* mod */); - - int firstKeyGroupOffset = -1; - int lastKeyGroupOffset = -1; - for (int i = 0; i < myMod; i++) { - int value = myBuffer.readInt(); - if (value != -1) { - int offset = value + myStartOffset; - if (firstKeyGroupOffset == -1) firstKeyGroupOffset = offset; - lastKeyGroupOffset = offset; - } - } - if (firstKeyGroupOffset == -1) { - return; - } - assert (firstKeyGroupOffset > myStartOffset); - assert (lastKeyGroupOffset > myStartOffset); - assert (lastKeyGroupOffset >= firstKeyGroupOffset); - - int firstValueOffset = -1; - - myBuffer.setPosition(firstKeyGroupOffset); - while (myBuffer.getPosition() <= lastKeyGroupOffset) { - int groupSize = myBuffer.readInt(); - for (int i = 0; i < groupSize; i++) { - dst.add(myKeyProvider.get(myBuffer)); - - int valueOffset = myBuffer.readInt(); /* value offset */ - if( firstValueOffset == -1 ) firstValueOffset = valueOffset + myStartOffset; - } - } - assert myBuffer.getPosition() == firstValueOffset; - } - catch (IOException e) { - LOG.error(e); - } - } - - private int readKeyGroupOffset(int hash) { - myBuffer.setPosition(myStartOffset + 4 /* mod */ + 4 * hash); - int offset = -1; - try { - offset = myBuffer.readInt(); - } - catch (IOException e) { - LOG.error(e); - } - if (offset == -1) return -1; - return offset + myStartOffset; - } - - private int hash(int hashCode) { - return Math.abs(hashCode) % myMod; - } -} diff --git a/platform/platform-impl/src/com/intellij/util/io/ByteBufferMapWriteHandler.java b/platform/platform-impl/src/com/intellij/util/io/ByteBufferMapWriteHandler.java deleted file mode 100644 index 3987c02cb676..000000000000 --- a/platform/platform-impl/src/com/intellij/util/io/ByteBufferMapWriteHandler.java +++ /dev/null @@ -1,112 +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.util.io; - -import com.intellij.openapi.diagnostic.Logger; - -import java.io.DataOutput; -import java.io.IOException; -import java.util.Arrays; - -class ByteBufferMapWriteHandler { - private static final Logger LOG = Logger.getInstance("#com.intellij.util.io.ByteBufferMapWriteHandler"); - - private final ByteBufferMap.ValueProvider myValueProvider; - private final WriteableMap myMap; - - private final int[] myKeyHashes; - private final int myMod; - private final DataOutput myOut; - - public ByteBufferMapWriteHandler(DataOutput stream, /*ByteBufferMap.KeyProvider keyProvider, */ByteBufferMap.ValueProvider valueProvider, WriteableMap map, double searchFactor) { - myValueProvider = valueProvider; - myMap = map; - - myKeyHashes = myMap.getHashCodesArray(); - int mod = (int)(myKeyHashes.length / searchFactor); - myMod = mod != 0 ? mod : 1; - myOut = stream; - } - - public void execute() throws IOException { - - executeImpl( true ); - } - - public int calcLength() throws IOException { - return executeImpl( false ); - } - - public int executeImpl( boolean write ) throws IOException { - if( write ) myOut.writeInt(myMod); - int offset = 4; - - int[] overflowList = new int[myKeyHashes.length]; - int[] firstOverflowElem = new int[myMod]; - int[] occurs = new int[myMod]; - Arrays.fill(firstOverflowElem, -1); - - // Creating hash table and overflow lists - for( int i = myKeyHashes.length-1; i >= 0; i-- ) { - int hashhash = hash(myKeyHashes[i]); - overflowList[i] = firstOverflowElem[hashhash]; - firstOverflowElem[hashhash] = i; - occurs[hashhash]++; - } - - offset += 4 * myMod; // hash table size - // writing hash table - for( int i = 0; i < myMod; i++ ) { - if( write ) myOut.writeInt( occurs[i] != 0 ? offset : -1 ); - if( occurs[i] != 0 ) offset += 4; // key group size, if key group present - int occurs_i = 0; - for( int j = firstOverflowElem[i]; j != -1; j = overflowList[j] ) { - offset += myMap.getKeyLength( j ) + 4 /* value offset */; - occurs_i++; - } - LOG.assertTrue( occurs_i == occurs[i] ); - } - - // writing key table - for( int i = 0; i < myMod; i++ ) { - if( occurs[i] == 0 ) continue; - - if( write ) myOut.writeInt( occurs[i] ); - for( int j = firstOverflowElem[i]; j != -1; j = overflowList[j] ) { - if( write ) { - myMap.writeKey( myOut, j ); - myOut.writeInt( offset ); - } - V value = myMap.getValue(j); - offset += myValueProvider.length(value); - } - } - - // writing value table - for( int i = 0; i < myMod; i++ ) { - for( int j = firstOverflowElem[i]; j != -1; j = overflowList[j] ) { - V value = myMap.getValue(j); - if( write ) myValueProvider.write( myOut, value ); - } - } - - return offset; // total resulting length - } - - private int hash(int hashCode){ - return Math.abs(hashCode) % myMod; - } -} diff --git a/platform/platform-impl/src/com/intellij/util/io/ByteBufferRADataInput.java b/platform/platform-impl/src/com/intellij/util/io/ByteBufferRADataInput.java deleted file mode 100644 index 65d5474a3c23..000000000000 --- a/platform/platform-impl/src/com/intellij/util/io/ByteBufferRADataInput.java +++ /dev/null @@ -1,110 +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.util.io; - -import com.intellij.openapi.diagnostic.Logger; - -import java.io.DataInputStream; -import java.io.IOException; -import java.nio.ByteBuffer; - -/** - * @author max - */ -public class ByteBufferRADataInput implements RandomAccessDataInput { - private static final Logger LOG = Logger.getInstance("com.intellij.util.io.ByteBufferRADataInput"); - - private final MappedBufferWrapper myBuffer; - - public ByteBufferRADataInput(MappedBufferWrapper buffer) { - myBuffer = buffer; - } - - public void setPosition(int pos) { - getBuffer().position(pos); - } - - public int getPosition() { - return getBuffer().position(); - } - - public void readFully(byte[] b) throws IOException { - getBuffer().get(b); - } - - public void readFully(byte[] b, int off, int len) throws IOException { - getBuffer().get(b, off, len); - } - - public int skipBytes(int n) throws IOException { - int newPos = getPosition() + n; - setPosition(newPos); - return newPos; - } - - public boolean readBoolean() throws IOException { - return getBuffer().get() == 1; - } - - public byte readByte() throws IOException { - return getBuffer().get(); - } - - public int readUnsignedByte() throws IOException { - return 0xFF & ((int)getBuffer().get()); - } - - public short readShort() throws IOException { - return getBuffer().getShort(); - } - - public int readUnsignedShort() throws IOException { - return 0xFFFF & ((int)getBuffer().getShort()); - } - - public char readChar() throws IOException { - return getBuffer().getChar(); - } - - public int readInt() throws IOException { - return getBuffer().getInt(); - } - - public long readLong() throws IOException { - return getBuffer().getLong(); - } - - public float readFloat() throws IOException { - return getBuffer().getFloat(); - } - - public double readDouble() throws IOException { - return getBuffer().getDouble(); - } - - public String readLine() throws IOException { - LOG.error("Not implemented"); - return null; - } - - public String readUTF() throws IOException { - return DataInputStream.readUTF(this); - } - - public ByteBuffer getBuffer() { - return myBuffer.buf(); - } -} diff --git a/platform/platform-impl/src/com/intellij/util/io/FileKeyProvider.java b/platform/platform-impl/src/com/intellij/util/io/FileKeyProvider.java deleted file mode 100644 index 5bffe1b1d568..000000000000 --- a/platform/platform-impl/src/com/intellij/util/io/FileKeyProvider.java +++ /dev/null @@ -1,61 +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.util.io; - -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.vfs.VirtualFile; -import gnu.trove.TObjectIntHashMap; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -public class FileKeyProvider implements ByteBufferMap.KeyProvider{ - private static final Logger LOG = Logger.getInstance("#com.intellij.util.io.FileKeyProvider"); - - private final VirtualFile[] myFileIndex; - private final TObjectIntHashMap myFileToIndexMap; - - public FileKeyProvider(VirtualFile[] fileIndex, TObjectIntHashMap fileToIndexMap) { - myFileIndex = fileIndex; - myFileToIndexMap = fileToIndexMap; - } - - public int hashCode(VirtualFile key) { - int index = myFileToIndexMap.get(key) - 1; - return index; - } - - public void write(DataOutput out, VirtualFile key) throws IOException { - int index = myFileToIndexMap.get(key) - 1; - LOG.assertTrue(index >= 0); - out.writeInt(index); - } - - public int length(VirtualFile key) { - return 4; - } - - public VirtualFile get(DataInput in) throws IOException { - int index = in.readInt(); - return myFileIndex[index]; - } - - public boolean equals(DataInput in, VirtualFile key) throws IOException { - int index = in.readInt(); - return key.equals(myFileIndex[index]); - } -} diff --git a/platform/platform-impl/src/com/intellij/util/io/IntArrayValueProvider.java b/platform/platform-impl/src/com/intellij/util/io/IntArrayValueProvider.java deleted file mode 100644 index 1a395c0d08ee..000000000000 --- a/platform/platform-impl/src/com/intellij/util/io/IntArrayValueProvider.java +++ /dev/null @@ -1,99 +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.util.io; - -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.util.ArrayUtil; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -public class IntArrayValueProvider implements ByteBufferMap.ValueProvider { - private static final Logger LOG = Logger.getInstance("#com.intellij.util.io.IntArrayValueProvider"); - public static final IntArrayValueProvider INSTANCE = new IntArrayValueProvider(-1); - - private final int myArraySize; - - public IntArrayValueProvider(int arraySize) { - myArraySize = arraySize; - } - - public void write(DataOutput out, int[] value) throws IOException { - //if (value instanceof IntArrayList) { - // IntArrayList list = (IntArrayList) value; - // LOG.assertTrue(myArraySize == -1 || list.size() == myArraySize); - // if (myArraySize == -1) out.writeInt(list.size()); - // for (int i = 0; i < list.size(); i++) { - // out.writeInt(list.get(i)); - // } - //} else if (value instanceof TIntArrayList) { - // TIntArrayList list = (TIntArrayList) value; - // LOG.assertTrue(myArraySize == -1 || list.size() == myArraySize); - // if (myArraySize == -1) out.writeInt(list.size()); - // for (int i = 0; i < list.size(); i++) { - // out.writeInt(list.get(i)); - // } - //} else { - int[] array = (int[])value; - LOG.assertTrue(myArraySize == -1 || array.length == myArraySize); - if (myArraySize == -1) out.writeInt(array.length); - for(int i = 0; i < array.length; i++){ - out.writeInt(array[i]); - } - //} - } - - public int length(int[] value) { - //if (value instanceof IntArrayList) { - // IntArrayList list = (IntArrayList) value; - // LOG.assertTrue(myArraySize == -1 || list.size() == myArraySize); - // - // if (myArraySize == -1) return 4 * (list.size() + 1); - // - // return 4 * myArraySize; - //} else if (value instanceof TIntArrayList) { - // TIntArrayList list = (TIntArrayList) value; - // LOG.assertTrue(myArraySize == -1 || list.size() == myArraySize); - // - // if (myArraySize == -1) return 4 * (list.size() + 1); - // - // return 4 * myArraySize; - //} else { - int[] array = (int[])value; - LOG.assertTrue(myArraySize == -1 || array.length == myArraySize); - - if (myArraySize == -1) return 4 * (array.length + 1); - - return 4 * myArraySize; - //} - } - - public int[] get(DataInput in) throws IOException { - final int[] result; - - if (myArraySize >= 0) { - result = ArrayUtil.newIntArray(myArraySize); - } else { - result = ArrayUtil.newIntArray(in.readInt()); - } - - for(int i = 0; i < result.length; i++){ - result[i] = in.readInt(); - } - return result; - } -} diff --git a/platform/platform-impl/src/com/intellij/util/io/IntValueProvider.java b/platform/platform-impl/src/com/intellij/util/io/IntValueProvider.java deleted file mode 100644 index 8c30fd88a055..000000000000 --- a/platform/platform-impl/src/com/intellij/util/io/IntValueProvider.java +++ /dev/null @@ -1,42 +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.util.io; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * @author max - */ -public class IntValueProvider implements ByteBufferMap.ValueProvider { - public static IntValueProvider INSTANCE = new IntValueProvider(); - - private IntValueProvider() { - } - - public void write(DataOutput out, Integer value) throws IOException { - out.writeInt(((Integer)value).intValue()); - } - - public int length(Integer value) { - return 4; - } - - public Integer get(DataInput in) throws IOException { - return new Integer(in.readInt()); - } -} diff --git a/platform/platform-impl/src/com/intellij/util/io/IntegerKeyProvider.java b/platform/platform-impl/src/com/intellij/util/io/IntegerKeyProvider.java deleted file mode 100644 index ff10086a1b74..000000000000 --- a/platform/platform-impl/src/com/intellij/util/io/IntegerKeyProvider.java +++ /dev/null @@ -1,54 +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.util.io; - -import com.intellij.openapi.diagnostic.Logger; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; - -/** - * @deprecated use {@link ByteBufferIntObjectMap} instead - */ -public class IntegerKeyProvider implements ByteBufferMap.KeyProvider { - private static final Logger LOG = Logger.getInstance("#com.intellij.util.io.StringKeyProvider"); - - public static final IntegerKeyProvider INSTANCE = new IntegerKeyProvider(); - - private IntegerKeyProvider() { - } - - public int hashCode(Integer key) { - return key.hashCode(); - } - - public void write(DataOutput out, Integer key) throws IOException { - out.writeInt(key.intValue()); - } - - public int length(Integer key) { - return 4; - } - - public Integer get(DataInput in) throws IOException { - return new Integer(in.readInt()); - } - - public boolean equals(DataInput in, Integer key) throws IOException { - return key.intValue() == in.readInt(); - } -} diff --git a/platform/platform-impl/src/com/intellij/util/io/StringKeyProvider.java b/platform/platform-impl/src/com/intellij/util/io/StringKeyProvider.java deleted file mode 100644 index f3a7e643aa1e..000000000000 --- a/platform/platform-impl/src/com/intellij/util/io/StringKeyProvider.java +++ /dev/null @@ -1,92 +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.util.io; - -import com.intellij.openapi.diagnostic.Logger; - -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.io.UnsupportedEncodingException; - -import org.jetbrains.annotations.NonNls; - -public class StringKeyProvider implements ByteBufferMap.KeyProvider{ - private static final Logger LOG = Logger.getInstance("#com.intellij.util.io.StringKeyProvider"); - - public static final StringKeyProvider INSTANCE = new StringKeyProvider(); - @NonNls public static final String UTF_8_CHARSET_NAME = "UTF-8"; - - private StringKeyProvider() { - } - - public int hashCode(String key) { - return key.hashCode(); - } - - public void write(DataOutput out, String key) throws IOException { - String keyString = (String)key; - byte[] keyBytes = keyString.getBytes(UTF_8_CHARSET_NAME); - out.writeInt(keyBytes.length); - out.write(keyBytes); - } - - public int length(String key) { - try{ - String keyString = (String)key; - byte[] keyBytes = keyString.getBytes(UTF_8_CHARSET_NAME); - return 4 + keyBytes.length; - } - catch(UnsupportedEncodingException e){ - LOG.error(e); - return 0; - } - } - - public String get(DataInput in) throws IOException { - int length = in.readInt(); - byte[] bytes = new byte[length]; - in.readFully(bytes); - try { - return new String(bytes, UTF_8_CHARSET_NAME); - } - catch (UnsupportedEncodingException e) { - LOG.error(e); - return null; - } - } - - public boolean equals(DataInput in, String key) throws IOException { - try { - String keyString = (String)key; - byte[] keyBytes = keyString.getBytes(UTF_8_CHARSET_NAME); - - int length = in.readInt(); - byte[] inputBytes = new byte[length]; - in.readFully(inputBytes); - if (length != keyBytes.length) return false; - for (int i = 0; i < length; i++) { - if (keyBytes[i] != inputBytes[i]) return false; - } - - return true; - } - catch (UnsupportedEncodingException e) { - LOG.error(e); - return false; - } - } -} diff --git a/platform/platform-impl/src/com/intellij/util/io/WriteableMapAdapter.java b/platform/platform-impl/src/com/intellij/util/io/WriteableMapAdapter.java deleted file mode 100644 index 2375d37232e9..000000000000 --- a/platform/platform-impl/src/com/intellij/util/io/WriteableMapAdapter.java +++ /dev/null @@ -1,54 +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.util.io; - -import java.io.DataOutput; -import java.io.IOException; -import java.util.Map; - -/** - * @author max - */ -public class WriteableMapAdapter implements WriteableMap { - private final Map myMap; - private final ByteBufferMap.KeyProvider myKeyProvider; - private final K[] myKeys; - - public WriteableMapAdapter(Map map, ByteBufferMap.KeyProvider provider) { - myMap = map; - myKeyProvider = provider; - myKeys = (K[]) myMap.keySet().toArray(); - } - - public int[] getHashCodesArray() { - int[] keyHashCodes = new int[ myKeys.length ]; - for( int i = 0; i < myKeys.length; i++ ) - keyHashCodes[i] = myKeyProvider.hashCode(myKeys[i]); - return keyHashCodes; - } - - public V getValue( int n ) { - return myMap.get( myKeys[n] ); - } - - public int getKeyLength( int n ) { - return myKeyProvider.length( myKeys[n] ); - } - - public void writeKey( DataOutput out, int n ) throws IOException { - myKeyProvider.write( out, myKeys[n] ); - } -} diff --git a/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java b/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java index 3f1faa390fbb..f051b7849536 100644 --- a/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java +++ b/platform/platform-impl/testSrc/com/intellij/openapi/editor/impl/softwrap/mapping/SoftWrapApplianceOnDocumentModificationTest.java @@ -420,6 +420,21 @@ public class SoftWrapApplianceOnDocumentModificationTest extends AbstractEditorP assertEquals(startOffset, myEditor.logicalPositionToOffset(myEditor.visualToLogicalPosition(new VisualPosition(2, 0)))); } + public void testFoldRegionThatStartsAtLineEnd() throws IOException { + String text = + "line1\n" + + "line2\n" + + "line3\n" + + "line4\n" + + "line5"; + + init(30, text); + int start = text.indexOf("line3") - 1; + addCollapsedFoldRegion(start, text.length(), "..."); + assertEquals(1, getSoftWrapModel().getRegisteredSoftWraps().size()); + assertEquals(start, getSoftWrapModel().getRegisteredSoftWraps().get(0).getStart()); + } + public void testHomeProcessing() throws IOException { String text = "class Test {\n" + diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java index 118d3202931d..a47d2d76d7e6 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestCase.java @@ -595,13 +595,6 @@ public abstract class PlatformTestCase extends UsefulTestCase implements DataPro public static File createTempDir(@NonNls final String prefix) throws IOException { final File tempDirectory = FileUtil.createTempDirectory(TEST_DIR_PREFIX + prefix, null); myFilesToDelete.add(tempDirectory); - // grand VFS refresh significantly slows down local tests and generally not needed - //ApplicationManager.getApplication().runWriteAction(new Runnable() { - // @Override - // public void run() { - // VirtualFileManager.getInstance().refresh(false); - // } - //}); return tempDirectory; } diff --git a/platform/util/src/com/intellij/util/io/MappedBufferWrapper.java b/platform/util/src/com/intellij/util/io/MappedBufferWrapper.java index 8114f53e3a3b..0cf5923e87d5 100644 --- a/platform/util/src/com/intellij/util/io/MappedBufferWrapper.java +++ b/platform/util/src/com/intellij/util/io/MappedBufferWrapper.java @@ -24,6 +24,7 @@ import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.NonNls; import java.io.File; +import java.io.IOException; import java.lang.reflect.Method; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; @@ -48,7 +49,7 @@ public abstract class MappedBufferWrapper { myLength = length; } - protected abstract MappedByteBuffer map(); + protected abstract MappedByteBuffer map() throws IOException; private static final int MAX_FORCE_ATTEMPTS = 10; @@ -63,7 +64,7 @@ public abstract class MappedBufferWrapper { return myBuffer; } - public ByteBuffer buf() { + public ByteBuffer buf() throws IOException { if (myBuffer == null) { myBuffer = map(); } diff --git a/platform/util/src/com/intellij/util/io/MappedFile.java b/platform/util/src/com/intellij/util/io/MappedFile.java deleted file mode 100644 index 494ffe9fa206..000000000000 --- a/platform/util/src/com/intellij/util/io/MappedFile.java +++ /dev/null @@ -1,355 +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.util.io; - -import com.intellij.openapi.Forceable; -import com.intellij.openapi.diagnostic.Logger; -import org.jetbrains.annotations.NonNls; - -import java.io.*; -import java.nio.ByteBuffer; -import java.nio.MappedByteBuffer; - -/** - * @author max - */ -public class MappedFile implements Forceable { - private static final Logger LOG = Logger.getInstance("#com.intellij.util.io.MappedFile"); - - private MappedBufferWrapper myHolder; - private final File myFile; - - private long myRealSize; - private long mySize; - private long myPosition; - private boolean myIsDirty = false; - - @NonNls private static final String UTF_8_CHARSET_NAME = "UTF-8"; - @NonNls private static final String RW = "rw"; - private final byte[] buffer = new byte[8]; - - public MappedFile(File file, int initialSize) throws IOException { - myFile = file; - if (!file.exists() || file.length() == 0) { - writeLength(0); - } - - myPosition = 0; - map(); - - mySize = readLength(); - if (mySize == 0) { - resize(initialSize); - } - } - - private long readLength() { - File lengthFile = getLengthFile(); - DataInputStream stream = null; - try { - stream = new DataInputStream(new FileInputStream(lengthFile)); - return stream.readLong(); - } - catch (IOException e) { - writeLength(myRealSize); - return myRealSize; - } - finally { - if (stream != null) { - try { - stream.close(); - } - catch (IOException e) { - LOG.error(e); - } - } - } - } - - private File getLengthFile() { - return new File(myFile.getPath() + ".len"); - } - - private void writeLength(final long len) { - File lengthFile = getLengthFile(); - DataOutputStream stream = null; - try { - stream = new DataOutputStream(new FileOutputStream(lengthFile)); - stream.writeLong(len); - } - catch (FileNotFoundException e) { - LOG.error(e); - } - catch (IOException e) { - LOG.error(e); - } - finally { - if (stream != null) { - try { - stream.close(); - } - catch (IOException e) { - LOG.error(e); - } - } - } - } - - private void map() { - myHolder = new ReadWriteMappedBufferWrapper(myFile); - myRealSize = myFile.length(); - if (LOG.isDebugEnabled()) { - LOG.assertTrue(myPosition > 0L && myPosition < myRealSize || myPosition == 0 && myRealSize == 0, "myPosition=" + myPosition + ", myRealSize=" + myRealSize); - } - myHolder.buf().position((int)myPosition); - } - - public short getShort(int index) throws IOException { - seek(index); - return readShort(); - } - - public short readShort() throws IOException { - get(buffer, 0, 2); - - return Bits.getShort(buffer, 0); - } - - public void putShort(int index, short value) throws IOException { - seek(index); - writeShort(value); - } - - public void writeShort(int value) throws IOException { - Bits.putShort(buffer, 0, (short)value); - put(buffer, 0, 2); - } - - public int getInt(int index) throws IOException { - seek(index); - return readInt(); - } - - public long getLong(final int index) throws IOException { - seek(index); - return readLong(); - } - - public void putInt(int index, int value) throws IOException { - seek(index); - writeInt(value); - } - - public void putLong(final int index, final long value) throws IOException { - seek(index); - writeLong(value); - } - - public byte get(int index) throws IOException { - seek(index); - return readByte(); - } - - public void put(int index, byte value) throws IOException { - seek(index); - writeByte(value); - } - - public void get(int index, byte[] dst, int offset, int length) throws IOException { - seek(index); - get(dst, offset, length); - } - - public void get(final byte[] dst, final int offset, final int length) throws IOException { - if (myPosition + length > mySize) { - throw new EOFException(); - } - - buf().get(dst, offset, length); - myPosition += length; - } - - public void put(int index, byte[] src, int offset, int length) throws IOException { - seek(index); - put(src, offset, length); - } - - public void seek(long pos) throws IOException { - ensureSize(pos); - buf().position((int)pos); - myPosition = pos; - if (pos > mySize) { - mySize = pos; - } - } - - private ByteBuffer buf() { - if (!isMapped()) { - map(); - } - - return myHolder.buf(); - } - - private void ensureSize(final long pos) throws IOException { - while (pos >= myRealSize) { - expand(); - } - } - - private void expand() throws IOException { - resize((int)((myRealSize + 1) * 13) >> 3); - } - - public void put(final byte[] src, final int offset, final int length) throws IOException { - ensureSize(myPosition + length); - myIsDirty = true; - buf().put(src, offset, length); - myPosition += length; - if (myPosition > mySize) { - mySize = myPosition; - } - } - - public void flush() { - if (myIsDirty) { - writeLength(mySize); - final ByteBuffer buf = buf(); - if (buf instanceof MappedByteBuffer) { - MappedBufferWrapper.tryForce(buf); - } - myIsDirty = false; - } - } - - public void force() { - flush(); - } - - public boolean isDirty() { - return myIsDirty; - } - - public void close() { - if (myIsDirty) { - writeLength(mySize); - } - unmap(); - } - - public void resize(int size) throws IOException { - final int current = (int)myRealSize; - if (current == size) return; - unmap(); - RandomAccessFile raf = new RandomAccessFile(myFile, RW); - try { - raf.setLength(size); - } - finally { - raf.close(); - } - map(); - } - - public final long length() { - return mySize; - } - - public long getFilePointer() { - return myPosition; - } - - public int readInt() throws IOException { - get(buffer, 0, 4); - return Bits.getInt(buffer, 0); - } - - public long readLong() throws IOException { - get(buffer, 0, 8); - return Bits.getLong(buffer, 0); - } - - public void writeInt(int value) throws IOException { - Bits.putInt(buffer, 0, value); - put(buffer, 0, 4); - } - - public void writeLong(long value) throws IOException { - Bits.putLong(buffer, 0, value); - put(buffer, 0, 8); - } - - public String readUTF() throws IOException { - try { - int len = readInt(); - byte[] bytes = new byte[ len ]; - get(bytes, 0, len); - return new String(bytes, UTF_8_CHARSET_NAME); - } - catch (UnsupportedEncodingException e) { - // Can't be - return ""; - } - } - - public void writeUTF(String value) throws IOException { - try { - final byte[] bytes = value.getBytes(UTF_8_CHARSET_NAME); - writeInt(bytes.length); - put(bytes, 0, bytes.length); - } - catch (UnsupportedEncodingException e) { - // Can't be - } - } - - public int readUnsignedShort() throws IOException { - get(buffer, 0, 2); - - int ch1 = buffer[0] & 0xff; - int ch2 = buffer[1] & 0xff; - return (ch1 << 8) + ch2; - } - - public char readChar() throws IOException { - return (char)readUnsignedShort(); - } - - public void writeChar(char value) throws IOException { - writeShort(value); - } - - public byte readByte() throws IOException { - get(buffer, 0, 1); - return buffer[0]; - } - - public void writeByte(byte value) throws IOException { - buffer[0] = value; - put(buffer, 0, 1); - } - - private void unmap() { - if (myHolder != null) { - /* flush(); TODO: Don't commit... */ - myHolder.unmap(); - } - } - - public boolean isMapped() { - return myHolder.isMapped(); - } -} diff --git a/platform/util/src/com/intellij/util/io/PagedFileStorage.java b/platform/util/src/com/intellij/util/io/PagedFileStorage.java index 5a985cceabf7..a3954c1b16ce 100644 --- a/platform/util/src/com/intellij/util/io/PagedFileStorage.java +++ b/platform/util/src/com/intellij/util/io/PagedFileStorage.java @@ -16,6 +16,7 @@ package com.intellij.util.io; import com.intellij.openapi.Forceable; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.util.containers.hash.LinkedHashMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -33,7 +34,12 @@ import java.util.Set; * @author max */ public class PagedFileStorage implements Forceable { - private final static int BUFFER_SIZE = 10 * 1024 * 1024; // 10M + + protected static final Logger LOG = Logger.getInstance("#com.intellij.util.io.PagedFileStorage"); + private static final int MEGABYTE = 1024 * 1024; + private final static int BUFFER_SIZE = 10 * MEGABYTE; + private final static int UPPER_LIMIT = 200 * MEGABYTE; + private final static int LOWER_LIMIT = 100 * MEGABYTE; private final StorageLock myLock; @@ -51,8 +57,9 @@ public class PagedFileStorage implements Forceable { final BuffersCache myBuffersCache = new BuffersCache(); private class BuffersCache extends MyCache { + public BuffersCache() { - super(20 * BUFFER_SIZE); + super(UPPER_LIMIT); } @NotNull @@ -65,7 +72,40 @@ public class PagedFileStorage implements Forceable { if (off > key.owner.length()) { throw new IndexOutOfBoundsException("off=" + off + " key.owner.length()=" + key.owner.length()); } - return new ReadWriteMappedBufferWrapper(key.owner.myFile, off, Math.min((int)(key.owner.length() - off), BUFFER_SIZE)); + ReadWriteMappedBufferWrapper wrapper = + new ReadWriteMappedBufferWrapper(key.owner.myFile, off, Math.min((int)(key.owner.length() - off), BUFFER_SIZE)); + IOException oome = null; + while (true) { + try { + // ensure it's allocated + wrapper.buf(); + if (oome != null) { + LOG.error("Successfully recovered OOME in memory mapping: -Xmx=" + Runtime.getRuntime().maxMemory() / MEGABYTE + "MB " + + "new size limit: " + mySizeLimit / MEGABYTE + "MB " + + "trying to allocate " + wrapper.myLength + " block"); + } + return wrapper; + } + catch (IOException e) { + if (e.getCause() instanceof OutOfMemoryError) { + oome = e; + if (mySizeLimit > LOWER_LIMIT) { + mySizeLimit -= BUFFER_SIZE; + } + long newSize = getSize() - BUFFER_SIZE; + if (newSize >= 0) { + ensureSize(newSize); + continue; // next try + } + else { + throw new MappingFailedException("Cannot recover from OOME in memory mapping: -Xmx=" + Runtime.getRuntime().maxMemory() / MEGABYTE + "MB " + + "new size limit: " + mySizeLimit / MEGABYTE + "MB " + + "trying to allocate " + wrapper.myLength + " block", e); + } + } + throw new MappingFailedException("Cannot map buffer", e); + } + } } public void onDropFromCache(PageKey key, MappedBufferWrapper buf) { @@ -106,7 +146,7 @@ public class PagedFileStorage implements Forceable { private final byte[] myTypedIOBuffer = new byte[8]; private boolean isDirty = false; private final File myFile; - private long mySize = -1; + protected long mySize = -1; @NonNls private static final String RW = "rw"; public PagedFileStorage(File file, StorageLock lock) throws IOException { @@ -133,6 +173,7 @@ public class PagedFileStorage implements Forceable { put(addr, myTypedIOBuffer, 0, 8); } + @SuppressWarnings({"UnusedDeclaration"}) public void putByte(final int addr, final byte b) { myTypedIOBuffer[0] = b; put(addr, myTypedIOBuffer, 0, 1); @@ -277,7 +318,12 @@ public class PagedFileStorage implements Forceable { } private ByteBuffer getBuffer(int page) { - return myLock.myBuffersCache.get(new PageKey(this, page)).buf(); + try { + return myLock.myBuffersCache.get(new PageKey(this, page)).buf(); + } + catch (IOException e) { + throw new MappingFailedException("Cannot map buffer", e); + } } public void force() { @@ -296,7 +342,7 @@ public class PagedFileStorage implements Forceable { private static abstract class MyCache { private final LinkedHashMap myMap; - private final long mySizeLimit; + protected long mySizeLimit; private long mySize; protected MyCache(long sizeLimit) { @@ -329,11 +375,19 @@ public class PagedFileStorage implements Forceable { wrapper = createValue(key); mySize += wrapper.myLength; myMap.put(key, wrapper); - while (mySize > mySizeLimit) { + ensureSize(mySizeLimit); + return wrapper; + } + + protected void ensureSize(long sizeLimit) { + while (mySize > sizeLimit) { // we still have to drop something myMap.doRemoveEldestEntry(); } - return wrapper; + } + + public long getSize() { + return mySize; } public Set> entrySet() { diff --git a/platform/util/src/com/intellij/util/io/ReadOnlyMappedBufferWrapper.java b/platform/util/src/com/intellij/util/io/ReadOnlyMappedBufferWrapper.java index f025447395be..9280bcaab5e4 100644 --- a/platform/util/src/com/intellij/util/io/ReadOnlyMappedBufferWrapper.java +++ b/platform/util/src/com/intellij/util/io/ReadOnlyMappedBufferWrapper.java @@ -30,22 +30,15 @@ public class ReadOnlyMappedBufferWrapper extends MappedBufferWrapper { super(file, pos, file.length() - pos); } - public MappedByteBuffer map() { + public MappedByteBuffer map() throws IOException { + FileInputStream stream = new FileInputStream(myFile); + FileChannel channel = stream.getChannel(); try { - FileInputStream stream = new FileInputStream(myFile); - FileChannel channel = stream.getChannel(); - try { - return channel.map(FileChannel.MapMode.READ_ONLY, myPosition, myLength); - } - finally { - channel.close(); - stream.close(); - } + return channel.map(FileChannel.MapMode.READ_ONLY, myPosition, myLength); } - catch (IOException e) { - final MappingFailedException mapFailed = new MappingFailedException("Mapping failed for: " + myFile.getPath(), e); - LOG.error(mapFailed); - throw mapFailed; + finally { + channel.close(); + stream.close(); } } } diff --git a/platform/util/src/com/intellij/util/io/ReadWriteMappedBufferWrapper.java b/platform/util/src/com/intellij/util/io/ReadWriteMappedBufferWrapper.java index 1e91397015e3..68367ac0f112 100644 --- a/platform/util/src/com/intellij/util/io/ReadWriteMappedBufferWrapper.java +++ b/platform/util/src/com/intellij/util/io/ReadWriteMappedBufferWrapper.java @@ -30,51 +30,25 @@ import java.nio.channels.FileChannel; public class ReadWriteMappedBufferWrapper extends MappedBufferWrapper { @NonNls private static final String RW = "rw"; - public ReadWriteMappedBufferWrapper(final File file) { - super(file, 0, file.length()); - } - public ReadWriteMappedBufferWrapper(final File file, int offset, int len) { super(file, offset, len); } - public MappedByteBuffer map() { - MappedByteBuffer buf; + public MappedByteBuffer map() throws IOException { + RandomAccessFile raf = null; + FileChannel channel = null; try { - buf = null; - RandomAccessFile raf = null; - FileChannel channel = null; - try { - raf = new RandomAccessFile(myFile, RW); - channel = raf.getChannel(); - buf = channel.map(FileChannel.MapMode.READ_WRITE, myPosition, myLength); + raf = new RandomAccessFile(myFile, RW); + channel = raf.getChannel(); + return channel.map(FileChannel.MapMode.READ_WRITE, myPosition, myLength); + } + finally { + if (channel != null) { + channel.close(); } - catch (IOException e) { - final MappingFailedException mapFailed = - new MappingFailedException("Mapping failed: " + myFile.getAbsolutePath() + ", position=" + myPosition + ", length=" + myLength, e); - LOG.error(mapFailed); - throw mapFailed; - } - finally { - if (channel != null) { - channel.close(); - } - if (raf != null) { - raf.close(); - } + if (raf != null) { + raf.close(); } } - catch (IOException e) { - buf = null; - } - - if (buf == null) { - final MappingFailedException mapFailed = - new MappingFailedException("Mapping failed: " + myFile.getAbsolutePath() + ", position=" + myPosition + ", length=" + myLength); - LOG.error(mapFailed); - throw mapFailed; - } - - return buf; } } \ No newline at end of file diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugSession.java b/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugSession.java index f924a5fb70a4..f8010f52b2a1 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugSession.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugSession.java @@ -16,16 +16,15 @@ package com.intellij.xdebugger; -import com.intellij.execution.ExecutionException; -import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.execution.configurations.RunProfile; +import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.openapi.project.Project; import com.intellij.xdebugger.breakpoints.XBreakpoint; import com.intellij.xdebugger.breakpoints.XLineBreakpoint; -import com.intellij.xdebugger.frame.XSuspendContext; import com.intellij.xdebugger.frame.XStackFrame; -import com.intellij.xdebugger.stepping.XSmartStepIntoVariant; +import com.intellij.xdebugger.frame.XSuspendContext; import com.intellij.xdebugger.stepping.XSmartStepIntoHandler; +import com.intellij.xdebugger.stepping.XSmartStepIntoVariant; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -64,6 +63,8 @@ public interface XDebugSession extends AbstractDebuggerSession { void pause(); void resume(); + void showExecutionPoint(XSourcePosition sourcePosition); + void showExecutionPoint(); void setCurrentStackFrame(@NotNull XStackFrame frame); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java index b4765e42e86e..8d66f86e78ee 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java @@ -344,6 +344,12 @@ public class XDebugSessionImpl implements XDebugSession { myDispatcher.getMulticaster().sessionResumed(); } + public void showExecutionPoint(XSourcePosition sourcePosition) { + XExecutionStack activeExecutionStack = mySuspendContext.getActiveExecutionStack(); + boolean isTopFrame = activeExecutionStack != null && activeExecutionStack.getTopFrame() == myCurrentStackFrame; + myDebuggerManager.setActiveSession(this, sourcePosition, !isTopFrame); + } + public void showExecutionPoint() { if (mySuspendContext != null) { XExecutionStack executionStack = mySuspendContext.getActiveExecutionStack(); diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerManagerImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerManagerImpl.java index 3dc3c8af5c73..2b410768f79b 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerManagerImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerManagerImpl.java @@ -68,7 +68,6 @@ public class XDebuggerManagerImpl extends XDebuggerManager implements ProjectCom private final ExecutionPointHighlighter myExecutionPointHighlighter; private XDebugSessionImpl myActiveSession; - public XDebuggerManagerImpl(final Project project, final StartupManager startupManager, MessageBus messageBus) { myProject = project; myBreakpointManager = new XBreakpointManagerImpl(project, this, startupManager); diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index 106bef988a7a..56df1c6e604b 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1722,9 +1722,6 @@ junit4.test.method.in.class.extending.junit3.testcase.problem.descriptor=@Test a equals.called.on.enum.constant.display.name='equals()' called on Enum value equals.called.on.enum.constant.problem.descriptor=#ref called on Enum value #loc equals.called.on.enum.constant.quickfix=Replace 'equals()' with '==' -unnecessary.annotation.parentheses.display.name=Unnecessary annotation parentheses -unnecessary.annotation.parentheses.problem.descriptor=#ref has unnecessary parentheses #loc -unnecessary.annotation.parameter.quickfix=Remove parentheses int.literal.may.be.long.literal.display.name=int literal cast to long could be long literal int.literal.may.be.long.literal.problem.descriptor=#ref could be replaced with ''{0}'' #loc int.literal.may.be.long.literal.quickfix=Replace with ''{0}'' @@ -1817,4 +1814,8 @@ cast.conflicts.with.instanceof.quickfix2=Replace instanceof ''{0}'' with ''{1}'' double.checked.locking.quickfix=Make ''{0}'' volatile double.literal.may.be.float.literal.display.name=double literal cast to long could be float literal double.literal.may.be.float.literal.problem.descriptor=#ref could be replaced with ''{0}'' #loc -double.literal.may.be.float.literal.quickfix=Replace with ''{0}'' \ No newline at end of file +double.literal.may.be.float.literal.quickfix=Replace with ''{0}'' +multiple.declaration.option=Ignore for loop declarations +simplifiable.annotation.display.name=Simplifiable annotation +simplifiable.annotation.problem.descriptor=Annotation #ref may be replaced with ''{0}'' +simplifiable.annotation.quickfix=Simplify annotation diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java index 1cdf74d1f5bb..666994a0303b 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java @@ -729,10 +729,10 @@ public class InspectionGadgetsPlugin implements ApplicationComponent, m_inspectionClasses.add(RedundantFieldInitializationInspection.class); m_inspectionClasses.add(RedundantImplementsInspection.class); m_inspectionClasses.add(ReturnThisInspection.class); + m_inspectionClasses.add(SimplifiableAnnotationInspection.class); m_inspectionClasses.add(TypeParameterExtendsObjectInspection.class); m_inspectionClasses.add(UnnecessarilyQualifiedInnerClassAccessInspection.class); m_inspectionClasses.add(UnnecessarilyQualifiedStaticUsageInspection.class); - m_inspectionClasses.add(UnnecessaryAnnotationParenthesesInspection.class); m_inspectionClasses.add(UnnecessaryBlockStatementInspection.class); m_inspectionClasses.add(UnnecessaryCallToStringValueOfInspection.class); m_inspectionClasses.add(UnnecessaryConstructorInspection.class); diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/NormalizeDeclarationFix.java b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/NormalizeDeclarationFix.java index 2808d4d99a74..5f5393c7f4e8 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/NormalizeDeclarationFix.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/fixes/NormalizeDeclarationFix.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2005 Dave Griffith + * Copyright 2003-2010 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,24 +17,99 @@ package com.siyeh.ig.fixes; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiVariable; +import com.intellij.psi.*; import com.intellij.util.IncorrectOperationException; import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.InspectionGadgetsBundle; import org.jetbrains.annotations.NotNull; public class NormalizeDeclarationFix extends InspectionGadgetsFix{ + @NotNull public String getName(){ return InspectionGadgetsBundle.message("normalize.declaration.quickfix"); } + @Override public void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException{ final PsiElement variableNameElement = descriptor.getPsiElement(); - final PsiVariable var = (PsiVariable) variableNameElement.getParent(); - assert var != null; - var.normalizeDeclaration(); + final PsiVariable parent = + (PsiVariable) variableNameElement.getParent(); + if (parent == null) { + return; + } + final PsiElement grandParent = parent.getParent(); + if (!(grandParent instanceof PsiDeclarationStatement)) { + return; + } + final PsiElement greatGrandParent = grandParent.getParent(); + if (greatGrandParent instanceof PsiForStatement) { + final PsiDeclarationStatement declarationStatement = + (PsiDeclarationStatement) grandParent; + splitMultipleDeclarationInForStatementInitialization( + declarationStatement); + return; + } + parent.normalizeDeclaration(); + } + + private static void splitMultipleDeclarationInForStatementInitialization( + PsiDeclarationStatement declarationStatement) { + final PsiElement forStatement = declarationStatement.getParent(); + final PsiElement[] declaredElements = + declarationStatement.getDeclaredElements(); + final Project project = forStatement.getProject(); + final PsiElementFactory factory = + JavaPsiFacade.getElementFactory(project); + final PsiElement greatGreatGrandParent = forStatement.getParent(); + final PsiBlockStatement blockStatement; + final PsiCodeBlock codeBlock; + if (!(greatGreatGrandParent instanceof PsiCodeBlock)) { + blockStatement = (PsiBlockStatement) + factory.createStatementFromText("{}", forStatement); + codeBlock = blockStatement.getCodeBlock(); + } else { + blockStatement = null; + codeBlock = null; + } + for (int i = 1; i < declaredElements.length; i++) { + final PsiElement declaredElement = declaredElements[i]; + if (!(declaredElement instanceof PsiVariable)) { + continue; + } + final PsiVariable variable = (PsiVariable) declaredElement; + final PsiType type = variable.getType(); + final String typeText = type.getCanonicalText(); + final StringBuilder newStatementText = + new StringBuilder(typeText); + newStatementText.append(' '); + newStatementText.append(variable.getName()); + final PsiExpression initializer = variable.getInitializer(); + if (initializer != null) { + newStatementText.append('='); + newStatementText.append(initializer.getText()); + } + newStatementText.append(';'); + final PsiStatement newStatement = + factory.createStatementFromText( + newStatementText.toString(), forStatement); + if (codeBlock == null) { + greatGreatGrandParent.addBefore(newStatement, forStatement); + } else { + codeBlock.add(newStatement); + } + } + for (int i = 1; i < declaredElements.length; i++) { + final PsiElement declaredElement = declaredElements[i]; + if (!(declaredElement instanceof PsiVariable)) { + continue; + } + declaredElement.delete(); + } + if (codeBlock != null) { + codeBlock.add(forStatement); + forStatement.replace(blockStatement); + } } } diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/MultipleDeclarationInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/MultipleDeclarationInspection.java index b5121ed5cd55..080785bb0b75 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/style/MultipleDeclarationInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/MultipleDeclarationInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2010 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ */ package com.siyeh.ig.style; +import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import com.intellij.psi.*; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; @@ -23,34 +24,51 @@ import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.fixes.NormalizeDeclarationFix; import org.jetbrains.annotations.NotNull; +import javax.swing.*; + public class MultipleDeclarationInspection extends BaseInspection { + @SuppressWarnings({"PublicField"}) + public boolean ignoreForLoopDeclarations = true; + + @Override @NotNull public String getDisplayName() { return InspectionGadgetsBundle.message( "multiple.declaration.display.name"); } + @Override @NotNull public String getID() { return "MultipleVariablesInDeclaration"; } + @Override @NotNull protected String buildErrorString(Object... infos) { return InspectionGadgetsBundle.message( "multiple.declaration.problem.descriptor"); } + @Override + public JComponent createOptionsPanel() { + return new SingleCheckboxOptionsPanel(InspectionGadgetsBundle.message( + "multiple.declaration.option"), + this, "ignoreForLoopDeclarations"); + } + + @Override public InspectionGadgetsFix buildFix(Object... infos) { return new NormalizeDeclarationFix(); } + @Override public BaseInspectionVisitor buildVisitor() { return new MultipleDeclarationVisitor(); } - private static class MultipleDeclarationVisitor + private class MultipleDeclarationVisitor extends BaseInspectionVisitor { @Override public void visitDeclarationStatement( @@ -60,19 +78,21 @@ public class MultipleDeclarationInspection extends BaseInspection { return; } final PsiElement parent = statement.getParent(); - if (parent instanceof PsiForStatement) { - final PsiForStatement forStatement = (PsiForStatement)parent; - final PsiStatement initialization = - forStatement.getInitialization(); - if (statement.equals(initialization)) { - return; - } + if (ignoreForLoopDeclarations && + parent instanceof PsiForStatement) { + return; } - final PsiElement[] declaredVars = statement.getDeclaredElements(); - for (int i = 1; i < declaredVars.length; i++) { + final PsiElement[] declaredElements = + statement.getDeclaredElements(); + for (int i = 1; i < declaredElements.length; i++) { //skip the first one; - final PsiLocalVariable var = (PsiLocalVariable)declaredVars[i]; - registerVariableError(var); + final PsiElement declaredElement = declaredElements[i]; + if (!(declaredElement instanceof PsiVariable)) { + continue; + } + final PsiVariable variable = + (PsiVariable) declaredElement; + registerVariableError(variable); } } @@ -87,7 +107,7 @@ public class MultipleDeclarationInspection extends BaseInspection { registerFieldError(field); } - public static boolean childrenContainTypeElement(PsiElement field) { + public boolean childrenContainTypeElement(PsiElement field) { final PsiElement[] children = field.getChildren(); for (PsiElement aChildren : children) { if (aChildren instanceof PsiTypeElement) { diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/SimplifiableAnnotationInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/SimplifiableAnnotationInspection.java new file mode 100644 index 000000000000..699fe826fc82 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/SimplifiableAnnotationInspection.java @@ -0,0 +1,137 @@ +/* + * Copyright 2010 Bas Leijdekkers + * + * 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.siyeh.ig.style; + +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.InspectionGadgetsFix; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +public class SimplifiableAnnotationInspection extends BaseInspection { + + @Nls + @NotNull + @Override + public String getDisplayName() { + return InspectionGadgetsBundle.message( + "simplifiable.annotation.display.name"); + } + + @NotNull + @Override + protected String buildErrorString(Object... infos) { + final String replacement = (String) infos[0]; + return InspectionGadgetsBundle.message( + "simplifiable.annotation.problem.descriptor", replacement); + } + + @Override + protected InspectionGadgetsFix buildFix(Object... infos) { + final String replacement = (String) infos[0]; + return new SimplifiableAnnotationFix(replacement); + } + + private static class SimplifiableAnnotationFix + extends InspectionGadgetsFix { + + private final String replacement; + + public SimplifiableAnnotationFix(String replacement) { + super(); + this.replacement = replacement; + } + + @NotNull + public String getName() { + return InspectionGadgetsBundle.message( + "simplifiable.annotation.quickfix"); + } + + @Override + protected void doFix(Project project, ProblemDescriptor descriptor) + throws IncorrectOperationException { + final PsiElement element = descriptor.getPsiElement(); + if (!(element instanceof PsiAnnotation)) { + return; + } + final PsiElementFactory factory = + JavaPsiFacade.getElementFactory(project); + final PsiAnnotation annotation = + factory.createAnnotationFromText(replacement, element); + element.replace(annotation); + } + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new SimplifiableAnnotationVisitor(); + } + + private static class SimplifiableAnnotationVisitor + extends BaseInspectionVisitor { + + @Override + public void visitAnnotation(PsiAnnotation annotation) { + super.visitAnnotation(annotation); + final PsiAnnotationParameterList parameterList = + annotation.getParameterList(); + final PsiJavaCodeReferenceElement nameReferenceElement = + annotation.getNameReferenceElement(); + if (nameReferenceElement == null) { + return; + } + final PsiNameValuePair[] attributes = parameterList.getAttributes(); + + final PsiElement[] annotationChildren = annotation.getChildren(); + if (annotationChildren.length >= 2) { + final PsiElement child = annotationChildren[1]; + if (child instanceof PsiWhiteSpace) { + final String replacementText; + if (attributes.length > 0) { + replacementText = '@' + nameReferenceElement.getText() + + parameterList.getText(); + } else { + replacementText = '@' + nameReferenceElement.getText(); + } + registerError(annotation, replacementText); + return; + } + } + if (attributes.length == 0) { + final PsiElement[] children = parameterList.getChildren(); + if (children.length <= 0) { + return; + } + registerError(annotation, '@' + nameReferenceElement.getText()); + } else if (attributes.length == 1) { + final PsiNameValuePair attribute = attributes[0]; + @NonNls final String name = attribute.getName(); + if (!"value".equals(name)) { + return; + } + registerError(annotation, '@' + nameReferenceElement.getText() + + '(' + attribute.getValue().getText() + ')'); + } + } + } +} diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnnecessaryAnnotationParenthesesInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnnecessaryAnnotationParenthesesInspection.java deleted file mode 100644 index e1a8badcb493..000000000000 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/style/UnnecessaryAnnotationParenthesesInspection.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2009 Bas Leijdekkers - * - * 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.siyeh.ig.style; - -import com.intellij.codeInspection.ProblemDescriptor; -import com.intellij.openapi.project.Project; -import com.intellij.psi.*; -import com.intellij.util.IncorrectOperationException; -import com.siyeh.InspectionGadgetsBundle; -import com.siyeh.ig.BaseInspection; -import com.siyeh.ig.BaseInspectionVisitor; -import com.siyeh.ig.InspectionGadgetsFix; -import org.jetbrains.annotations.Nls; -import org.jetbrains.annotations.NotNull; - -public class UnnecessaryAnnotationParenthesesInspection extends BaseInspection { - - @Override - @Nls - @NotNull() - public String getDisplayName() { - return InspectionGadgetsBundle.message( - "unnecessary.annotation.parentheses.display.name"); - } - - @Override - @NotNull - protected String buildErrorString(Object... infos) { - return InspectionGadgetsBundle.message( - "unnecessary.annotation.parentheses.problem.descriptor"); - } - - @Override - protected InspectionGadgetsFix buildFix(Object... infos) { - return new UnnecessaryAnnotationParenthesesFix(); - } - - private static class UnnecessaryAnnotationParenthesesFix - extends InspectionGadgetsFix { - - @NotNull - public String getName() { - return InspectionGadgetsBundle.message( - "unnecessary.annotation.parameter.quickfix"); - } - - @Override - protected void doFix(Project project, ProblemDescriptor descriptor) - throws IncorrectOperationException { - final PsiElement element = descriptor.getPsiElement(); - if (!(element instanceof PsiAnnotationParameterList)) { - return; - } - final PsiElement[] children = element.getChildren(); - for (PsiElement child : children) { - child.delete(); - } - } - } - - @Override - public BaseInspectionVisitor buildVisitor() { - return new UnnecessaryAnnotatinoParenthesesVisitor(); - } - - private static class UnnecessaryAnnotatinoParenthesesVisitor - extends BaseInspectionVisitor { - - @Override - public void visitAnnotation(PsiAnnotation annotation) { - super.visitAnnotation(annotation); - final PsiJavaCodeReferenceElement reference = - annotation.getNameReferenceElement(); - if (reference == null) { - return; - } - final PsiAnnotationParameterList parameterList = - annotation.getParameterList(); - final PsiElement[] children = parameterList.getChildren(); - if (children.length == 0) { - return; - } - final PsiNameValuePair[] nameValuePairs = - parameterList.getAttributes(); - if (nameValuePairs.length > 0) { - return; - } - final PsiElement target = reference.resolve(); - if (!(target instanceof PsiClass)) { - return; - } - final PsiClass annotationClass = (PsiClass) target; - final PsiMethod[] methods = annotationClass.getMethods(); - for (PsiMethod method : methods) { - if (!(method instanceof PsiAnnotationMethod)) { - continue; - } - final PsiAnnotationMethod annotationMethod = - (PsiAnnotationMethod) method; - final PsiAnnotationMemberValue defaultValue = - annotationMethod.getDefaultValue(); - if (defaultValue == null) { - return; - } - } - registerError(parameterList); - } - } -} diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/SimplifiableAnnotation.html b/plugins/InspectionGadgets/src/inspectionDescriptions/SimplifiableAnnotation.html new file mode 100644 index 000000000000..45847f410cfb --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/SimplifiableAnnotation.html @@ -0,0 +1,8 @@ + +
+ +This inspection reports annotations which can be simplified to their 'single element' +or 'marker' shorthand form. Annotation that contain whitespace between the @-sign and the name +of the annotation are also reported. +
New in 10.1, Powered by InspectionGadgets
+ \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/simplifiable_annotation/SimplifiableAnnotation.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/simplifiable_annotation/SimplifiableAnnotation.java new file mode 100644 index 000000000000..8a3eb8a8c2e4 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/simplifiable_annotation/SimplifiableAnnotation.java @@ -0,0 +1,10 @@ +package com.siyeh.igtest.style.simplifiable_annotation; + +public class SimplifiableAnnotation { + + @ SuppressWarnings(value = "blabla") + @ Deprecated() + Object foo() { + return null; + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/simplifiable_annotation/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/simplifiable_annotation/expected.xml new file mode 100644 index 000000000000..cebedfafc00b --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/simplifiable_annotation/expected.xml @@ -0,0 +1,16 @@ + + + + SimplifiableAnnotation.java + 5 + Simplifiable annotation + Annotation <code>@ SuppressWarnings(value = "blabla")</code> may be replaced with '@SuppressWarnings(value = "blabla")' + + + + SimplifiableAnnotation.java + 6 + Simplifiable annotation + Annotation <code>@ Deprecated()</code> may be replaced with '@Deprecated' + + \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_annotation_parentheses/UnnecessaryAnnotationParentheses.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_annotation_parentheses/UnnecessaryAnnotationParentheses.java deleted file mode 100644 index 435f3ef55143..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_annotation_parentheses/UnnecessaryAnnotationParentheses.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.siyeh.igtest.style.unnecessary_annotation_parentheses; - -import org.jetbrains.annotations.NotNull; - -public class UnnecessaryAnnotationParentheses { - - @Deprecated() - Object foo() { - return null; - } - - @SuppressWarnings() - String s; -} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_annotation_parentheses/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_annotation_parentheses/expected.xml deleted file mode 100644 index 405af641dfec..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/unnecessary_annotation_parentheses/expected.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - UnnecessaryAnnotationParentheses.java - 7 - Unnecessary annotation parentheses - <code>()</code> has unnecessary parentheses #loc - - \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/SimplifiableAnnotationInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/SimplifiableAnnotationInspectionTest.java new file mode 100644 index 000000000000..646cf7ec830e --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/SimplifiableAnnotationInspectionTest.java @@ -0,0 +1,11 @@ +package com.siyeh.ig.style; + +import com.IGInspectionTestCase; + +public class SimplifiableAnnotationInspectionTest extends IGInspectionTestCase { + + public void test() throws Exception { + doTest("com/siyeh/igtest/style/simplifiable_annotation", + new SimplifiableAnnotationInspection()); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/UnnecessaryAnnotationParenthesesInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/UnnecessaryAnnotationParenthesesInspectionTest.java deleted file mode 100644 index 9a41f42962d1..000000000000 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/UnnecessaryAnnotationParenthesesInspectionTest.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.siyeh.ig.style; - -import com.IGInspectionTestCase; - -public class UnnecessaryAnnotationParenthesesInspectionTest extends IGInspectionTestCase { - - public void test() throws Exception { - doTest("com/siyeh/igtest/style/unnecessary_annotation_parentheses", - new UnnecessaryAnnotationParenthesesInspection()); - } -} \ No newline at end of file diff --git a/plugins/android/src/org/jetbrains/android/run/AndroidRunningState.java b/plugins/android/src/org/jetbrains/android/run/AndroidRunningState.java index a583f1ebb399..38b51eaaa21e 100644 --- a/plugins/android/src/org/jetbrains/android/run/AndroidRunningState.java +++ b/plugins/android/src/org/jetbrains/android/run/AndroidRunningState.java @@ -613,6 +613,29 @@ public abstract class AndroidRunningState implements RunProfileState, AndroidDeb return true; } + private class MyISyncProgressMonitor implements SyncService.ISyncProgressMonitor { + @Override + public void start(int totalWork) { + } + + @Override + public void stop() { + } + + @Override + public boolean isCanceled() { + return myStopped; + } + + @Override + public void startSubTask(String name) { + } + + @Override + public void advance(int work) { + } + } + private boolean uploadApp(IDevice device, String remotePath, String localPath) throws IOException { if (myStopped) return false; getProcessHandler().notifyTextAvailable("Uploading file\n\tlocal path: " + localPath + "\n\tremote path: " + remotePath + '\n', STDOUT); @@ -621,12 +644,57 @@ public abstract class AndroidRunningState implements RunProfileState, AndroidDeb getProcessHandler().notifyTextAvailable("Can't upload file: device is not available.\n", STDERR); return false; } - SyncService.SyncResult result = service.pushFile(localPath, remotePath, SyncService.getNullProgressMonitor()); - if (result.getCode() != SyncService.RESULT_OK) { - getProcessHandler().notifyTextAvailable("Can't upload file: " + result.getMessage() + ".\n", STDERR); - return false; + SyncService.SyncResult result = service.pushFile(localPath, remotePath, new MyISyncProgressMonitor()); + int code = result.getCode(); + String errorMessage; + switch (code) { + case SyncService.RESULT_OK: + return true; + case SyncService.RESULT_CANCELED: + errorMessage = "Command canceled"; + break; + case SyncService.RESULT_CONNECTION_ERROR: + errorMessage = "Connection error"; + break; + case SyncService.RESULT_CONNECTION_TIMEOUT: + errorMessage = "Connection timeout"; + break; + case SyncService.RESULT_FILE_READ_ERROR: + errorMessage = "Cannot read the file"; + break; + case SyncService.RESULT_FILE_WRITE_ERROR: + errorMessage = "Cannot write the file"; + break; + case SyncService.RESULT_LOCAL_IS_DIRECTORY: + errorMessage = "Local is directory"; + break; + case SyncService.RESULT_NO_DIR_TARGET: + errorMessage = "Target directory not found"; + break; + case SyncService.RESULT_NO_LOCAL_FILE: + errorMessage = "Local file not found"; + break; + case SyncService.RESULT_NO_REMOTE_OBJECT: + errorMessage = "No remote object"; + break; + case SyncService.RESULT_REMOTE_IS_FILE: + errorMessage = "Remote is a file"; + break; + case SyncService.RESULT_REMOTE_PATH_ENCODING: + errorMessage = "Incorrect remote path encoding"; + break; + case SyncService.RESULT_REMOTE_PATH_LENGTH: + errorMessage = "Incorrect remote path length"; + break; + case SyncService.RESULT_TARGET_IS_FILE: + errorMessage = "Target is a file"; + break; + default: + errorMessage = "Can't upload file"; } - return true; + getProcessHandler() + .notifyTextAvailable(errorMessage + (result.getMessage() != null ? "\n" + result.getMessage() + "\n" : "\n"), STDERR); + return false; } @SuppressWarnings({"DuplicateThrows"}) @@ -676,13 +744,13 @@ public abstract class AndroidRunningState implements RunProfileState, AndroidDeb executeDeviceCommandAndWriteToConsole(device, "pm install -r \"" + remotePath + '\"', receiver); if (myStopped) return false; }*/ - if (!isSuccess(receiver)) { + /*if (!isSuccess(receiver)) { getProcessHandler().notifyTextAvailable("Can't reinstall application. Installing from scratch.\n", STDOUT); executeDeviceCommandAndWriteToConsole(device, "pm uninstall \"" + remotePath + '\"', receiver); if (myStopped) return false; executeDeviceCommandAndWriteToConsole(device, "pm install \"" + remotePath + '\"', receiver); if (myStopped) return false; - } + }*/ boolean success = isSuccess(receiver); getProcessHandler().notifyTextAvailable(receiver.output.toString(), success ? STDOUT : STDERR); return success; diff --git a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdk.java b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdk.java index 6ccea9c53dda..079fdfc678d1 100644 --- a/plugins/android/src/org/jetbrains/android/sdk/AndroidSdk.java +++ b/plugins/android/src/org/jetbrains/android/sdk/AndroidSdk.java @@ -17,6 +17,7 @@ package org.jetbrains.android.sdk; import com.android.ddmlib.AndroidDebugBridge; +import com.android.ddmlib.DdmPreferences; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.ISdkLog; import com.android.sdklib.SdkConstants; @@ -145,6 +146,7 @@ public abstract class AndroidSdk { String adbPath = getAdbPath(); if (!myDdmLibInitialized) { myDdmLibInitialized = true; + DdmPreferences.setTimeOut(AndroidUtils.TIMEOUT); AndroidDebugBridge.init(AndroidEnableDdmsAction.isDdmsEnabled()); AndroidDebugBridge.createBridge(adbPath, true); } diff --git a/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java b/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java index 38eda83180d4..282462bf5874 100644 --- a/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java +++ b/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java @@ -119,7 +119,7 @@ public class AndroidUtils { public static final String EXT_NATIVE_LIB = "so"; @NonNls public static final String RES_OVERLAY_DIR_NAME = "res-overlay"; - private static final int TIMEOUT = 30000; + public static final int TIMEOUT = 30000; private AndroidUtils() { } diff --git a/plugins/git4idea/src/META-INF/plugin.xml b/plugins/git4idea/src/META-INF/plugin.xml index 318a2eb588e8..5a69476e65c8 100644 --- a/plugins/git4idea/src/META-INF/plugin.xml +++ b/plugins/git4idea/src/META-INF/plugin.xml @@ -104,6 +104,10 @@ + + diff --git a/plugins/git4idea/src/git4idea/GitVcs.java b/plugins/git4idea/src/git4idea/GitVcs.java index 98d0f8df9e8c..661c18cf1f55 100644 --- a/plugins/git4idea/src/git4idea/GitVcs.java +++ b/plugins/git4idea/src/git4idea/GitVcs.java @@ -58,13 +58,14 @@ import com.intellij.util.containers.ComparatorDelegate; import com.intellij.util.containers.Convertor; import com.intellij.util.ui.UIUtil; import git4idea.annotate.GitAnnotationProvider; +import git4idea.branch.GitBranchWidget; +import git4idea.branch.GitBranches; import git4idea.changes.GitChangeProvider; import git4idea.changes.GitChangeUtils; import git4idea.changes.GitCommittedChangeListProvider; import git4idea.changes.GitOutgoingChangesProvider; import git4idea.checkin.GitCheckinEnvironment; import git4idea.checkin.GitCommitAndPushExecutor; -import git4idea.checkout.branches.GitCurrentBranchWidget; import git4idea.commands.GitCommand; import git4idea.commands.GitSimpleHandler; import git4idea.config.GitExecutableValidator; @@ -145,10 +146,14 @@ public class GitVcs extends AbstractVcs { private boolean isActivated; // If true, the vcs was activated private GitExecutableValidator myExecutableValidator; private RepositoryChangeListener myIndexChangeListener; - private GitCurrentBranchWidget myCurrentBranchWidget; + private GitBranchWidget myBranchWidget; - public static GitVcs getInstance(@NotNull Project project) { - return (GitVcs)ProjectLevelVcsManager.getInstance(project).findVcsByName(NAME); + @Nullable + public static GitVcs getInstance(Project project) { + if (project == null || project.isDisposed()) { + return null; + } + return (GitVcs) ProjectLevelVcsManager.getInstance(project).findVcsByName(NAME); } public GitVcs(@NotNull Project project, @@ -203,8 +208,11 @@ public class GitVcs extends AbstractVcs { * * @param task the task to run */ - public void runInBackground(Task.Backgroundable task) { - myTaskQueue.run(task); + public static void runInBackground(Task.Backgroundable task) { + GitVcs vcs = getInstance(task.getProject()); + if (vcs != null) { + vcs.myTaskQueue.run(task); + } } /** @@ -431,9 +439,6 @@ public class GitVcs extends AbstractVcs { protected void shutdown() throws VcsException { } - /** - * {@inheritDoc} - */ @Override protected void activate() { isActivated = true; @@ -456,17 +461,14 @@ public class GitVcs extends AbstractVcs { NewGitUsersComponent.getInstance(myProject).activate(); GitProjectLogManager.getInstance(myProject).activate(); + GitBranches.getInstance(myProject).activate(this); StatusBar statusBar = WindowManager.getInstance().getStatusBar(myProject); if (statusBar != null) { - myCurrentBranchWidget = new GitCurrentBranchWidget(myProject); - statusBar.addWidget(myCurrentBranchWidget, "after " + (SystemInfo.isMac ? "Encoding" : "InsertOverwrite"), myProject); - addGitReferenceListener(myCurrentBranchWidget); + myBranchWidget = new GitBranchWidget(myProject); + statusBar.addWidget(myBranchWidget, "after " + (SystemInfo.isMac ? "Encoding" : "InsertOverwrite"), myProject); } } - /** - * {@inheritDoc} - */ @Override protected void deactivate() { isActivated = false; @@ -491,11 +493,11 @@ public class GitVcs extends AbstractVcs { NewGitUsersComponent.getInstance(myProject).deactivate(); GitProjectLogManager.getInstance(myProject).deactivate(); + GitBranches.getInstance(myProject).deactivate(); StatusBar statusBar = WindowManager.getInstance().getStatusBar(myProject); - if (statusBar != null && myCurrentBranchWidget != null) { - statusBar.removeWidget(myCurrentBranchWidget.ID()); - removeGitReferenceListener(myCurrentBranchWidget); - myCurrentBranchWidget = null; + if (statusBar != null && myBranchWidget != null) { + statusBar.removeWidget(myBranchWidget.ID()); + myBranchWidget = null; } } diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchWidget.java b/plugins/git4idea/src/git4idea/branch/GitBranchWidget.java new file mode 100644 index 000000000000..734e8d44b7d9 --- /dev/null +++ b/plugins/git4idea/src/git4idea/branch/GitBranchWidget.java @@ -0,0 +1,141 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package git4idea.branch; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.fileEditor.FileEditorManagerEvent; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.wm.StatusBarWidget; +import com.intellij.openapi.wm.impl.status.EditorBasedWidget; +import com.intellij.util.Consumer; +import git4idea.GitBranch; +import org.jetbrains.annotations.NotNull; + +import java.awt.event.MouseEvent; + +/** + * Status bar widget which displays the current branch for the file currently open in the editor. + * @author Kirill Likhodedov + */ +public class GitBranchWidget extends EditorBasedWidget implements StatusBarWidget.TextPresentation, StatusBarWidget.Multiframe, + GitBranchesListener { + + private volatile String myCurrentBranchName = ""; + private final GitBranches myBranches; + + public GitBranchWidget(Project project) { + super(project); + myBranches = GitBranches.getInstance(project); + myBranches.addListener(this); + } + + @Override + public StatusBarWidget copy() { + return new GitBranchWidget(getProject()); + } + + @NotNull + @Override + public String ID() { + return GitBranchWidget.class.getName(); + } + + @Override + public WidgetPresentation getPresentation(@NotNull PlatformType type) { + return this; + } + + @Override + public void selectionChanged(FileEditorManagerEvent event) { + update(); + } + + @Override + public void fileOpened(FileEditorManager source, VirtualFile file) { + update(); + } + + @Override + public void fileClosed(FileEditorManager source, VirtualFile file) { + update(); + } + + @NotNull + @Override + public String getText() { + final String text = myCurrentBranchName; + return StringUtil.isEmpty(text) ? "" : "Git: " + text; + } + + @NotNull + @Override + public String getMaxPossibleText() { + return "Git: abcdefghij"; + } + + @Override + public float getAlignment() { + return 0; + } + + @Override + public String getTooltipText() { + return "Current Git branch"; + } + + @Override + // Updates branch information on click + public Consumer getClickConsumer() { + return new Consumer() { + public void consume(MouseEvent mouseEvent) { + update(); + } + }; + } + + @Override + public void branchConfigurationChanged() { + update(); + } + + @Override + public void dispose() { + myBranches.removeListener(this); + } + + private void update() { + ApplicationManager.getApplication().invokeLater(new Runnable() { + public void run() { + final GitBranch currentBranch = myBranches.getCurrentBranch(getSelectedFile()); + String currentBranchName = currentBranch != null ? currentBranch.getName() : null; + if (currentBranchName == null) { + currentBranchName = ""; + } + myCurrentBranchName = currentBranchName; + myStatusBar.updateWidget(ID()); + } + }, new Condition() { + public boolean value(Object o) { + Project project = getProject(); + return isDisposed() || (project != null) && ((!project.isOpen()) || project.isDisposed()) || myStatusBar == null; + } + }); + } +} diff --git a/plugins/git4idea/src/git4idea/branch/GitBranches.java b/plugins/git4idea/src/git4idea/branch/GitBranches.java new file mode 100644 index 000000000000..8b3cd9c6b140 --- /dev/null +++ b/plugins/git4idea/src/git4idea/branch/GitBranches.java @@ -0,0 +1,172 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package git4idea.branch; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.AbstractVcs; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.VcsRoot; +import com.intellij.openapi.vcs.changes.ChangeListManager; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.EventDispatcher; +import git4idea.GitBranch; +import git4idea.GitVcs; +import git4idea.vfs.GitReferenceListener; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * Container and tracker of git branches information. + * Listens to branch change and updates information here. + * Subscribe a {@link GitBranchesListener} to get notified for current branch and other branch configuration changes. + * @author Kirill Likhodedov + */ +public class GitBranches implements GitReferenceListener { + private static final Logger LOG = Logger.getInstance(GitBranches.class.getName()); + private final Project myProject; + private final ProjectLevelVcsManager myVcsManager; + + private final EventDispatcher myListeners = EventDispatcher.create(GitBranchesListener.class); + private Map myCurrentBranches = new HashMap(); + private final Object myCurrentBranchesLock = new Object(); + private ChangeListManager myChangeListManager; + private GitVcs myVcs; + + public GitBranches(Project project, ChangeListManager changeListManager, ProjectLevelVcsManager vcsManager) { + myProject = project; + myChangeListManager = changeListManager; + myVcsManager = vcsManager; + } + + public static GitBranches getInstance(Project project) { + return ServiceManager.getService(project, GitBranches.class); + } + + @Override + public void referencesChanged(VirtualFile root) { + updateBranchesInfo(root); + } + + public void activate(GitVcs vcs) { + myVcs = vcs; + myVcs.addGitReferenceListener(this); + } + + public void deactivate() { + if (myVcs != null) { + myVcs.removeGitReferenceListener(this); + } + } + + /** + * Returns branch that is active (current) in the repository in which the given file resides. + * @param file file to determine branch. + * @return current branch or null if the file is null, not under git vcs, unversioned, or branch information is not available for it. + */ + @Nullable + public GitBranch getCurrentBranch(VirtualFile file) { + if (file == null) { return null; } + final AbstractVcs vcs = myVcsManager.getVcsFor(file); + if (vcs == null || !(vcs instanceof GitVcs)) { return null; } + final VirtualFile vcsRoot = myVcsManager.getVcsRootFor(file); + if (vcsRoot == null) { return null; } + if (myChangeListManager.isUnversioned(file)) { return null; } + + synchronized (myCurrentBranchesLock) { + return myCurrentBranches.get(vcsRoot); + } + } + + public void addListener(GitBranchesListener listener) { + myListeners.addListener(listener); + } + + public void removeListener(GitBranchesListener listener) { + myListeners.removeListener(listener); + } + + /** + * Updates branch information for the given root. + * If root is null, updates branch information for all Git roots in the project. + * @see #fullyUpdateBranchesInfo(java.util.Collection) + */ + private void updateBranchesInfo(final VirtualFile root) { + if (root == null) { // all roots may be affected + Collection roots = new ArrayList(1); + for (VcsRoot vcsRoot : myVcsManager.getAllVcsRoots()) { + if (vcsRoot.vcs != null && vcsRoot.vcs instanceof GitVcs && vcsRoot.path != null) { + roots.add(vcsRoot.path); + } + } + fullyUpdateBranchesInfo(roots); + return; + } + + final Task.Backgroundable task = new Task.Backgroundable(myProject, "") { + @Override public void run(@NotNull ProgressIndicator indicator) { + try { + GitBranch currentBranch = GitBranch.current(myProject, root); + synchronized (myCurrentBranchesLock) { + myCurrentBranches.put(root, currentBranch); + } + notifyListeners(); + } catch (VcsException e) { + LOG.info("Exception while trying to get current branch for root " + root, e); + // doing nothing - null will be set to myCurrentBranchName + } + } + }; + GitVcs.runInBackground(task); + } + + private void fullyUpdateBranchesInfo(final Collection roots) { + if (roots == null) { return; } + final Task.Backgroundable task = new Task.Backgroundable(myProject, "") { + @Override public void run(@NotNull ProgressIndicator indicator) { + Map currentBranches = new HashMap(); + for (VirtualFile root : roots) { + try { + GitBranch currentBranch = GitBranch.current(myProject, root); + currentBranches.put(root, currentBranch); + notifyListeners(); + } catch (VcsException e) { + LOG.info("Exception while trying to get current branch for root " + root, e); + // doing nothing - null will be set to myCurrentBranchName + } + } + synchronized (myCurrentBranchesLock) { + myCurrentBranches = currentBranches; + } + } + }; + GitVcs.runInBackground(task); + } + + private void notifyListeners() { + myListeners.getMulticaster().branchConfigurationChanged(); + } + +} diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchesListener.java b/plugins/git4idea/src/git4idea/branch/GitBranchesListener.java new file mode 100644 index 000000000000..cc4cec12092a --- /dev/null +++ b/plugins/git4idea/src/git4idea/branch/GitBranchesListener.java @@ -0,0 +1,27 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package git4idea.branch; + +import java.util.EventListener; + +/** + * GitBranchesListener listens to events related to Git branches. + * Change of active branch, branch creation, etc. + * @author Kirill Likhodedov + */ +public interface GitBranchesListener extends EventListener { + void branchConfigurationChanged(); +} diff --git a/plugins/git4idea/src/git4idea/changes/GitChangeProvider.java b/plugins/git4idea/src/git4idea/changes/GitChangeProvider.java index c1c4d1e5cdbb..3ab1a0fbf050 100644 --- a/plugins/git4idea/src/git4idea/changes/GitChangeProvider.java +++ b/plugins/git4idea/src/git4idea/changes/GitChangeProvider.java @@ -19,8 +19,20 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; -import com.intellij.openapi.vcs.*; -import com.intellij.openapi.vcs.changes.*; +import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vcs.FilePathImpl; +import com.intellij.openapi.vcs.FileStatus; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.VcsKey; +import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vcs.changes.ChangeListManager; +import com.intellij.openapi.vcs.changes.ChangeListManagerGate; +import com.intellij.openapi.vcs.changes.ChangeProvider; +import com.intellij.openapi.vcs.changes.ChangelistBuilder; +import com.intellij.openapi.vcs.changes.ChangesUtil; +import com.intellij.openapi.vcs.changes.VcsDirtyScope; +import com.intellij.openapi.vcs.changes.VcsModifiableDirtyScope; import com.intellij.openapi.vfs.VirtualFile; import git4idea.GitContentRevision; import git4idea.GitRevisionNumber; @@ -125,6 +137,10 @@ public class GitChangeProvider implements ChangeProvider { } public void unversioned(final VirtualFile vf) { + // NB: There was an exception that happened several times: vf == null. + // Populating myUnversioned in the ChangeCollector makes nulls not possible in myUnversioned, + // so proposing that the exception was fixed. + // More detailed analysis will be needed in case the exception appears again. 2010-12-09. myDirty.remove(new FilePathImpl(vf)); } diff --git a/plugins/git4idea/src/git4idea/checkin/GitPushActiveBranchesDialog.java b/plugins/git4idea/src/git4idea/checkin/GitPushActiveBranchesDialog.java index 2d85d6b95e87..c7c33029829c 100644 --- a/plugins/git4idea/src/git4idea/checkin/GitPushActiveBranchesDialog.java +++ b/plugins/git4idea/src/git4idea/checkin/GitPushActiveBranchesDialog.java @@ -21,6 +21,7 @@ import com.intellij.notification.NotificationType; import com.intellij.notification.Notifications; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; @@ -101,6 +102,7 @@ public class GitPushActiveBranchesDialog extends DialogWrapper { private JRadioButton myStashRadioButton; // Save files policy option private JRadioButton myShelveRadioButton; private GitVcs myVcs; + private static final Logger LOG = Logger.getInstance(GitPushActiveBranchesDialog.class.getName()); /** * A modification of Runnable with the roots-parameter. @@ -232,6 +234,7 @@ public class GitPushActiveBranchesDialog extends DialogWrapper { final Task.Backgroundable rebaseAndPushTask = new Task.Backgroundable(myProject, GitBundle.getString("push.active.fetching")) { public void run(@NotNull ProgressIndicator indicator) { List exceptions = new ArrayList(); + List pushExceptions = new ArrayList(); for (int i = 0; i < 3; i++) { final RebaseInfo rebaseInfo = collectRebaseInfo(); @@ -251,6 +254,7 @@ public class GitPushActiveBranchesDialog extends DialogWrapper { "Pushed " + commitsNum + " " + StringUtil.pluralize("commit", commitsNum) + "."); return; } + pushExceptions = new ArrayList(exceptions); exceptions.clear(); } @@ -270,7 +274,7 @@ public class GitPushActiveBranchesDialog extends DialogWrapper { GitUtil.refreshFiles(myProject, rebaseInfo.roots); } } - notifyException("Failed to push", exceptions); + notifyException("Failed to push", pushExceptions); } }; myVcs.runInBackground(rebaseAndPushTask); @@ -280,11 +284,15 @@ public class GitPushActiveBranchesDialog extends DialogWrapper { * Notifies about errors during background rebase & push tasks. */ private void notifyException(String title, Collection exceptions) { - final String content = StringUtil.join(exceptions, new Function() { + String content = StringUtil.join(exceptions, new Function() { @Override public String fun(VcsException e) { return e.getLocalizedMessage(); } }, "
"); + if (StringUtil.isEmptyOrSpaces(content)) { + content = title; + } + LOG.info(title + " || " + content); Notifications.Bus.notify(new Notification(GitVcs.IMPORTANT_ERROR_NOTIFICATION, title, content, NotificationType.ERROR), NotificationDisplayType.STICKY_BALLOON, myProject); } diff --git a/plugins/git4idea/src/git4idea/checkout/GitCheckoutProvider.java b/plugins/git4idea/src/git4idea/checkout/GitCheckoutProvider.java index cd97d1bf84f2..db814e08ebf9 100644 --- a/plugins/git4idea/src/git4idea/checkout/GitCheckoutProvider.java +++ b/plugins/git4idea/src/git4idea/checkout/GitCheckoutProvider.java @@ -15,9 +15,7 @@ */ package git4idea.checkout; -import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.CheckoutProvider; import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; @@ -28,6 +26,8 @@ import git4idea.actions.BasicAction; import git4idea.commands.GitCommand; import git4idea.commands.GitHandlerUtil; import git4idea.commands.GitLineHandler; +import git4idea.commands.GitTask; +import git4idea.commands.GitTaskResult; import git4idea.config.GitVersion; import git4idea.i18n.GitBundle; import org.jetbrains.annotations.NotNull; @@ -74,26 +74,26 @@ public class GitCheckoutProvider implements CheckoutProvider { final String originName, final String parentDirectory) { final GitLineHandler handler = clone(project, sourceRepositoryURL, new File(parentDirectory), directoryName, originName); - handler.addLineListener(new GitHandlerUtil.GitLineHandlerListenerProgress(ProgressManager.getInstance().getProgressIndicator(), handler, "git clone", true)); - new Task.Backgroundable(project, GitBundle.message("cloning.repository", sourceRepositoryURL), true) { - @Override public void run(@NotNull ProgressIndicator indicator) { - GitHandlerUtil.runInCurrentThread(handler, indicator, true, "git clone"); - } - @Override public void onSuccess() { - destinationParent.refresh(true, true, new Runnable() { - public void run() { - if (project.isOpen() && (! project.isDisposed()) && (! project.isDefault())) { - final VcsDirtyScopeManager mgr = VcsDirtyScopeManager.getInstance(project); - mgr.fileDirty(destinationParent); + GitTask task = new GitTask(project, handler, GitBundle.message("cloning.repository", sourceRepositoryURL)); + task.executeAsync(new GitTask.ResultHandler() { + @Override + public void run(GitTaskResult result) { + if (result == GitTaskResult.OK) { + destinationParent.refresh(true, true, new Runnable() { + public void run() { + if (project.isOpen() && (!project.isDisposed()) && (!project.isDefault())) { + final VcsDirtyScopeManager mgr = VcsDirtyScopeManager.getInstance(project); + mgr.fileDirty(destinationParent); + } } - } - }); - listener.directoryCheckedOut(new File(parentDirectory, directoryName)); - listener.checkoutCompleted(); + }); + listener.directoryCheckedOut(new File(parentDirectory, directoryName)); + listener.checkoutCompleted(); + } } - }.queue(); + }); } /** diff --git a/plugins/git4idea/src/git4idea/checkout/GitCloneDialog.java b/plugins/git4idea/src/git4idea/checkout/GitCloneDialog.java index fbbe62c3045c..2b5b3f48a31f 100644 --- a/plugins/git4idea/src/git4idea/checkout/GitCloneDialog.java +++ b/plugins/git4idea/src/git4idea/checkout/GitCloneDialog.java @@ -17,16 +17,24 @@ package git4idea.checkout; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.*; +import com.intellij.openapi.ui.ComponentWithBrowseButton; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.ui.TextComponentAccessor; +import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.vfs.VirtualFile; import git4idea.commands.GitCommand; -import git4idea.commands.GitHandlerUtil; import git4idea.commands.GitSimpleHandler; +import git4idea.commands.GitTask; +import git4idea.commands.GitTaskResult; import git4idea.i18n.GitBundle; import git4idea.validators.GitBranchNameValidator; import org.jetbrains.annotations.NonNls; -import javax.swing.*; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JTextField; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import java.awt.event.ActionEvent; @@ -163,14 +171,17 @@ public class GitCloneDialog extends DialogWrapper { myTestButton.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent e) { myTestURL = myRepositoryURL.getText(); - String output = GitHandlerUtil - .doSynchronously(checkRepository(myProject, myTestURL), GitBundle.message("clone.testing", myTestURL), "connection test"); - if (output != null) { + GitSimpleHandler handler = new GitSimpleHandler(myProject, new File("."), GitCommand.LS_REMOTE); + handler.addParameters(myTestURL, "master"); + + GitTask task = new GitTask(myProject, handler, GitBundle.message("clone.testing", myTestURL)); + GitTaskResult result = task.execute(); + + if (result.isOK()) { Messages.showInfoMessage(myTestButton, GitBundle.message("clone.test.success.message", myTestURL), GitBundle.getString("clone.test.success")); myTestResult = Boolean.TRUE; - } - else { + } else { myTestResult = Boolean.FALSE; } updateOkButton(); diff --git a/plugins/git4idea/src/git4idea/checkout/branches/GitCurrentBranchWidget.java b/plugins/git4idea/src/git4idea/checkout/branches/GitCurrentBranchWidget.java deleted file mode 100644 index ebca1eec9e8f..000000000000 --- a/plugins/git4idea/src/git4idea/checkout/branches/GitCurrentBranchWidget.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright 2000-2010 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package git4idea.checkout.branches; - -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.fileEditor.FileEditorManagerEvent; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.Task; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vcs.AbstractVcs; -import com.intellij.openapi.vcs.CalledInAwt; -import com.intellij.openapi.vcs.ProjectLevelVcsManager; -import com.intellij.openapi.vcs.VcsException; -import com.intellij.openapi.vcs.VcsRoot; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.wm.StatusBarWidget; -import com.intellij.openapi.wm.impl.status.EditorBasedWidget; -import com.intellij.util.Consumer; -import git4idea.GitBranch; -import git4idea.GitVcs; -import git4idea.vfs.GitReferenceListener; -import org.jetbrains.annotations.NotNull; - -import java.awt.event.MouseEvent; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; - -/** - * Status bar widget which displays the current branch. - * @author Kirill Likhodedov - */ -public class GitCurrentBranchWidget extends EditorBasedWidget implements StatusBarWidget.TextPresentation, GitReferenceListener, StatusBarWidget.Multiframe { - - private ProjectLevelVcsManager myVcsManager; - private AtomicReference myCurrentBranchName = new AtomicReference(""); - private static final Logger LOG = Logger.getInstance(GitCurrentBranchWidget.class.getName()); - private final Map myCurrentBranches = new HashMap(); - - public GitCurrentBranchWidget(Project project) { - super(project); - myVcsManager = ProjectLevelVcsManager.getInstance(project); - updateBranchInfo(null); - } - - @Override - public StatusBarWidget copy() { - return new GitCurrentBranchWidget(getProject()); - } - - @NotNull - @Override - public String ID() { - return "git4idea.GitCurrentBranchWidget"; - } - - @Override - public WidgetPresentation getPresentation(@NotNull PlatformType type) { - return this; - } - - @Override - public void selectionChanged(FileEditorManagerEvent event) { - updateUI(); - } - - @Override - public void fileOpened(FileEditorManager source, VirtualFile file) { - updateUI(); - } - - @Override - public void fileClosed(FileEditorManager source, VirtualFile file) { - updateUI(); - } - - @Override - public void referencesChanged(VirtualFile root) { - updateBranchInfo(root); - } - - @NotNull - @Override - public String getText() { - final String text = myCurrentBranchName.get(); - return StringUtil.isEmpty(text) ? "" : "Git: " + text; - } - - @NotNull - @Override - public String getMaxPossibleText() { - return "Git: abcdefghij"; - } - - @Override - public float getAlignment() { - return 0; - } - - @Override - public String getTooltipText() { - return "Current Git branch"; - } - - @Override - // Updates branch information on click - public Consumer getClickConsumer() { - return new Consumer() { - public void consume(MouseEvent mouseEvent) { - updateUI(); - } - }; - } - - @CalledInAwt - private void updateUI() { - final VirtualFile file = getSelectedFile(); - final Project project = getProject(); - if (file == null || project == null || isDisposed() || !project.isOpen() || project.isDisposed() || myStatusBar == null) { - return; - } - - String currentBranchName = null; - final AbstractVcs vcs = myVcsManager.getVcsFor(file); - if (vcs != null && vcs instanceof GitVcs) { - final VirtualFile root = myVcsManager.getVcsRootFor(file); - if (root != null) { - final GitBranch currentBranch = myCurrentBranches.get(root); - if (currentBranch != null) { - currentBranchName = currentBranch.getName(); - } - } - } - if (currentBranchName == null) { - currentBranchName = ""; - } - myCurrentBranchName.set(currentBranchName); - myStatusBar.updateWidget(ID()); - } - - private void updateBranchInfo(VirtualFile root) { - final Collection roots = new ArrayList(1); - if (root == null) { // all roots may be affected - for (VcsRoot vcsRoot : myVcsManager.getAllVcsRoots()) { - if (vcsRoot.vcs != null && vcsRoot.vcs instanceof GitVcs && vcsRoot.path != null) { - roots.add(vcsRoot.path); - } - } - } else { - roots.add(root); - } - - final Project project = getProject(); - final Task.Backgroundable task = new Task.Backgroundable(project, "Loading Git branch info") { - @Override public void run(@NotNull ProgressIndicator indicator) { - for (VirtualFile root : roots) { - try { - GitBranch currentBranch = GitBranch.current(project, root); - synchronized (myCurrentBranches) { - myCurrentBranches.put(root, currentBranch); - } - } catch (VcsException e) { - LOG.info("Exception while trying to get current branch for root " + root, e); - } - } - ApplicationManager.getApplication().invokeLater(new Runnable() { - public void run() { - updateUI(); - } - }); - } - }; - if (project != null) { - GitVcs.getInstance(project).runInBackground(task); - } - } - -} diff --git a/plugins/git4idea/src/git4idea/commands/GitBinaryHandler.java b/plugins/git4idea/src/git4idea/commands/GitBinaryHandler.java index a86dbc02ccad..fbd0aa75443f 100644 --- a/plugins/git4idea/src/git4idea/commands/GitBinaryHandler.java +++ b/plugins/git4idea/src/git4idea/commands/GitBinaryHandler.java @@ -15,6 +15,7 @@ */ package git4idea.commands; +import com.intellij.execution.ExecutionException; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.VcsException; @@ -82,6 +83,10 @@ public class GitBinaryHandler extends GitHandler { super(project, vcsRoot, command); } + @Override + protected Process startProcess() throws ExecutionException { + return myCommandLine.createProcess(); + } /** * {@inheritDoc} @@ -132,7 +137,7 @@ public class GitBinaryHandler extends GitHandler { * {@inheritDoc} */ @Override - protected void destroyProcess() { + public void destroyProcess() { myProcess.destroy(); } diff --git a/plugins/git4idea/src/git4idea/commands/GitHandler.java b/plugins/git4idea/src/git4idea/commands/GitHandler.java index 900e9d2cb4b5..fa7f28ede7c0 100644 --- a/plugins/git4idea/src/git4idea/commands/GitHandler.java +++ b/plugins/git4idea/src/git4idea/commands/GitHandler.java @@ -15,6 +15,7 @@ */ package git4idea.commands; +import com.intellij.execution.ExecutionException; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; @@ -397,7 +398,7 @@ public abstract class GitHandler { } myCommandLine.setEnvParams(myEnv); // start process - myProcess = myCommandLine.createProcess(); + myProcess = startProcess(); startHandlingStreams(); } catch (Throwable t) { @@ -410,8 +411,10 @@ public abstract class GitHandler { } } + protected abstract Process startProcess() throws ExecutionException; + /** - * Start handling streams for the handler + * Start handling process output streams for the handler. */ protected abstract void startHandlingStreams(); @@ -438,7 +441,7 @@ public abstract class GitHandler { /** * Destroy process */ - protected abstract void destroyProcess(); + public abstract void destroyProcess(); /** * @return exit code for process if it is available diff --git a/plugins/git4idea/src/git4idea/commands/GitTask.java b/plugins/git4idea/src/git4idea/commands/GitTask.java new file mode 100644 index 000000000000..85a288f11983 --- /dev/null +++ b/plugins/git4idea/src/git4idea/commands/GitTask.java @@ -0,0 +1,260 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package git4idea.commands; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.vcs.VcsException; +import git4idea.GitVcs; +import git4idea.i18n.GitBundle; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.atomic.AtomicReference; + +/** + * A Task to run the given GitHandler with ability to cancel it. + * Cancellation is implemented with a {@link java.util.Timer} which checks whether the ProgressIndicator was cancelled and kills + * the GitHandler in that case. + * + * A GitTask may be executed synchronously ({@link #execute()} or asynchronously ({@link #executeAsync(GitTask.ResultHandler)}. + * Result of the execution is encapsulated in {@link GitTaskResult}. + * + * @see {@link git4idea.commands.GitHandler#kill()} + * @author Kirill Likhodedov + */ +public class GitTask { + + private final Project myProject; + private final GitHandler myHandler; + private final String myTitle; + private final AtomicReference myResult = new AtomicReference(GitTaskResult.INITIAL); + + public interface ResultHandler { + void run(GitTaskResult result); + } + + public GitTask(Project project, GitHandler handler, String title) { + myProject = project; + myHandler = handler; + myTitle = title; + } + + /** + * Executes this task synchronously, with a modal progress dialog. + * @return Result of the task execution. + */ + public GitTaskResult execute() { + ModalTask task = new ModalTask(myProject, myHandler, myTitle) { + public void execute(ProgressIndicator indicator) { + GitHandlerUtil.runInCurrentThread(myHandler, indicator, true, myTitle); + } + + @Override + public void onSuccess() { + if (!myHandler.errors().isEmpty()) { + myResult.set(GitTaskResult.GIT_ERROR); + } else { + myResult.set(GitTaskResult.OK); + } + } + + @Override + public void onCancel() { + myResult.set(GitTaskResult.CANCELLED); + } + }; + + addListeners(task); + ProgressManager.getInstance().run(task); + return myResult.get(); + } + + /** + * Executes this task asynchronously, in backgrond. Calls the resultHandler when finished. + * @param resultHandler callback called after the task has finished or was cancelled by user or automatically. + */ + public void executeAsync(final ResultHandler resultHandler) { + BackgroundableTask task = new BackgroundableTask(myProject, myHandler, myTitle) { + public void execute(ProgressIndicator indicator) { + GitHandlerUtil.runInCurrentThread(myHandler, indicator, true, myTitle); + } + + @Override + public void onSuccess() { + if (!myHandler.errors().isEmpty()) { // TODO: handle errors smarter: an error may be not a complete failure. + myResult.set(GitTaskResult.GIT_ERROR); + } else { + myResult.set(GitTaskResult.OK); + } + resultHandler.run(myResult.get()); + } + + @Override + public void onCancel() { + myResult.set(GitTaskResult.CANCELLED); + resultHandler.run(GitTaskResult.CANCELLED); + } + }; + + addListeners(task); + GitVcs.getInstance(myProject).runInBackground(task); + } + + private void addListeners(final TaskExecution task) { + // When receives an error line, adds a VcsException to the GitHandler. + final GitLineHandlerListener errorListener = new GitLineHandlerListener() { + @Override + public void processTerminated(int exitCode) { + if (exitCode != 0 && !myHandler.isIgnoredErrorCode(exitCode)) { + if (myHandler.errors().isEmpty()) { + myHandler.addError(new VcsException(GitBundle.message("git.error.exit", exitCode))); + } + } + } + + @Override + public void startFailed(Throwable exception) { + myHandler.addError(new VcsException("Git start failed: " + exception.getMessage(), exception)); + } + + @Override + public void onLineAvailable(String line, Key outputType) { + if (GitHandlerUtil.isErrorLine(line.trim())) { + myHandler.addError(new VcsException(line)); + } + } + }; + + myHandler.addListener(errorListener); + if (myHandler instanceof GitLineHandler) { + ((GitLineHandler)myHandler).addLineListener(errorListener); + } + + // disposes the timer + myHandler.addListener(new GitHandlerListener() { + @Override + public void processTerminated(int exitCode) { + task.dispose(); + } + + @Override + public void startFailed(Throwable exception) { + task.dispose(); + } + }); + } + + /** + * We're using this interface here to work with Task, because standard {@link Task#run(com.intellij.openapi.progress.ProgressIndicator)} + * is busy with timers. + */ + private interface TaskExecution { + void execute(ProgressIndicator indicator); + void dispose(); + } + + // To add to {@link com.intellij.openapi.progress.BackgroundTaskQueue} a task must be {@link Task.Backgroundable}, + // so we can't have a single class representing a task: we have BackgroundableTask and ModalTask. + // To minimize code duplication we use GitTaskDelegate. + + private abstract class BackgroundableTask extends Task.Backgroundable implements TaskExecution { + private GitTaskDelegate myDelegate; + + public BackgroundableTask(@Nullable final Project project, @NotNull GitHandler handler, @NotNull final String processTitle) { + super(project, processTitle, true); + myDelegate = new GitTaskDelegate(myProject, handler, this); + } + + @Override + public final void run(@NotNull ProgressIndicator indicator) { + myDelegate.run(indicator); + } + + @Override + public void dispose() { + Disposer.dispose(myDelegate); + } + } + + private abstract class ModalTask extends Task.Modal implements TaskExecution { + private GitTaskDelegate myDelegate; + + public ModalTask(@Nullable final Project project, @NotNull GitHandler handler, @NotNull final String processTitle) { + super(project, processTitle, true); + myDelegate = new GitTaskDelegate(myProject, handler, this); + } + + @Override + public final void run(@NotNull ProgressIndicator indicator) { + myDelegate.run(indicator); + } + + @Override + public void dispose() { + Disposer.dispose(myDelegate); + } + } + + /** + * Does the work which is common for BackgrounableTask and ModalTask. + * Actually - starts a timer which checks if current progress indicator is cancelled. + * If yes, kills the GitHandler. + */ + private static class GitTaskDelegate implements Disposable { + private GitHandler myHandler; + private ProgressIndicator myIndicator; + private TaskExecution myTask; + private Timer myTimer; + private Project myProject; + + public GitTaskDelegate(Project project, GitHandler handler, TaskExecution task) { + myProject = project; + myHandler = handler; + myTask = task; + Disposer.register(myProject, this); + } + + public void run(ProgressIndicator indicator) { + myIndicator = indicator; + myTimer = new Timer(); + myTimer.schedule(new TimerTask() { + @Override + public void run() { + if (myIndicator != null && myIndicator.isCanceled()) { + if (myHandler != null) { + myHandler.destroyProcess(); + } + Disposer.dispose(GitTaskDelegate.this); + } + } + }, 0, 200); + myTask.execute(indicator); + } + + public void dispose() { + myTimer.cancel(); + } + } + +} diff --git a/plugins/git4idea/src/git4idea/commands/GitTaskResult.java b/plugins/git4idea/src/git4idea/commands/GitTaskResult.java new file mode 100644 index 000000000000..864a7b739d36 --- /dev/null +++ b/plugins/git4idea/src/git4idea/commands/GitTaskResult.java @@ -0,0 +1,27 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package git4idea.commands; + +/** +* @author Kirill Likhodedov +*/ +public enum GitTaskResult { + INITIAL, WORKING, OK, EXCEPTION, GIT_ERROR, TIMEOUT, CANCELLED, TERMINATED; + + public boolean isOK() { + return this == OK; + } +} diff --git a/plugins/git4idea/src/git4idea/commands/GitTextHandler.java b/plugins/git4idea/src/git4idea/commands/GitTextHandler.java index 8a21b78c5570..89f61e383390 100644 --- a/plugins/git4idea/src/git4idea/commands/GitTextHandler.java +++ b/plugins/git4idea/src/git4idea/commands/GitTextHandler.java @@ -15,10 +15,13 @@ */ package git4idea.commands; +import com.intellij.execution.ExecutionException; +import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.process.OSProcessHandler; import com.intellij.execution.process.ProcessEvent; +import com.intellij.execution.process.ProcessHandler; import com.intellij.execution.process.ProcessListener; -import com.intellij.openapi.diagnostic.Logger; +import com.intellij.execution.process.RunnerMediator; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VirtualFile; @@ -31,44 +34,28 @@ import java.nio.charset.Charset; * The handler for git commands with text outputs */ public abstract class GitTextHandler extends GitHandler { - /** - * the logger - */ - private static final Logger log = Logger.getInstance(GitTextHandler.class.getName()); - /** * wrapped process handler */ // note that access is safe because it accessed in unsynchronized block only after process is started, and it does not change after that @SuppressWarnings({"FieldAccessedSynchronizedAndUnsynchronized"}) private OSProcessHandler myHandler; - /** - * The constructor from super - * - * @param project the project - * @param directory the command directory - * @param command the command - */ protected GitTextHandler(@NotNull Project project, @NotNull File directory, @NotNull GitCommand command) { super(project, directory, command); } - /** - * The constructor - * - * @param project the project - * @param vcsRoot the vcs root - * @param command the command to run - */ protected GitTextHandler(final Project project, final VirtualFile vcsRoot, final GitCommand command) { super(project, vcsRoot, command); } - /** - * {@inheritDoc} - */ + @Override + protected Process startProcess() throws ExecutionException { + final ProcessHandler processHandler = new MyRunnerMediator().createProcess(myCommandLine); + myHandler = (MyOSProcessHandler)processHandler; + return myHandler.getProcess(); + } + protected void startHandlingStreams() { - myHandler = new MyOSProcessHandler(myProcess, myCommandLine.getCommandLineString(), getCharset()); myHandler.addProcessListener(new ProcessListener() { public void startNotified(final ProcessEvent event) { // do nothing @@ -108,31 +95,28 @@ public abstract class GitTextHandler extends GitHandler { */ protected abstract void onTextAvailable(final String text, final Key outputType); - /** - * {@inheritDoc} - */ - protected void destroyProcess() { - try { - myHandler.destroyProcess(); - } - catch (Exception e) { - log.warn("Exception during cancel", e); - } + public void destroyProcess() { + myHandler.destroyProcess(); } - /** - * {@inheritDoc} - */ protected void waitForProcess() { - OSProcessHandler handler = myHandler; - myHandler = null; - handler.waitFor(); + myHandler.waitFor(); } - private static class MyOSProcessHandler extends OSProcessHandler { + /** + * RunnerMediator that attaches our MyProcessHandler to the process instead of the standard CustomDestroyProcessHandler. + */ + private class MyRunnerMediator extends RunnerMediator { + @Override + protected ProcessHandler createProcessHandler(@NotNull Process process, @NotNull GeneralCommandLine commandLine) { + return new MyOSProcessHandler(process, commandLine, getCharset()); + } + } + + private static class MyOSProcessHandler extends RunnerMediator.CustomDestroyProcessHandler { private final Charset myCharset; - public MyOSProcessHandler(Process process, String commandLine, Charset charset) { + public MyOSProcessHandler(Process process, GeneralCommandLine commandLine, Charset charset) { super(process, commandLine); myCharset = charset; } diff --git a/plugins/git4idea/src/git4idea/update/GitBaseRebaseProcess.java b/plugins/git4idea/src/git4idea/update/GitBaseRebaseProcess.java index a59f0cccec03..ea9d0d7de72d 100644 --- a/plugins/git4idea/src/git4idea/update/GitBaseRebaseProcess.java +++ b/plugins/git4idea/src/git4idea/update/GitBaseRebaseProcess.java @@ -26,7 +26,12 @@ import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.AbstractVcsHelper; import com.intellij.openapi.vcs.VcsException; -import com.intellij.openapi.vcs.changes.*; +import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vcs.changes.ChangeListManagerEx; +import com.intellij.openapi.vcs.changes.ContentRevision; +import com.intellij.openapi.vcs.changes.InvokeAfterUpdateMode; +import com.intellij.openapi.vcs.changes.LocalChangeList; +import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; import com.intellij.openapi.vcs.changes.shelf.ShelveChangesManager; import com.intellij.openapi.vcs.changes.shelf.ShelvedChangeList; import com.intellij.openapi.vfs.LocalFileSystem; @@ -47,7 +52,16 @@ import git4idea.ui.GitConvertFilesDialog; import git4idea.ui.GitUIUtil; import java.io.File; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.TreeSet; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -126,6 +140,7 @@ public abstract class GitBaseRebaseProcess { * @param roots the vcs roots */ public void doUpdate(ProgressIndicator progressIndicator, Set roots) { + LOG.info("GitBaseRebaseProcess.doUpdate started"); ProjectManagerEx projectManager = ProjectManagerEx.getInstanceEx(); projectManager.blockReloadingProjectOnExternalChanges(); this.myProgressIndicator = progressIndicator; @@ -244,6 +259,7 @@ public abstract class GitBaseRebaseProcess { * Restore project changes after update */ private void restoreProjectChangesAfterUpdate() { + LOG.info("GitBaseRebaseProcess.restoreProjectChangesAfterUpdate update policy: " + getUpdatePolicy() + " myShelvedChangeList: " + myShelvedChangeList); if (mySkippedCommits.size() > 0) { GitSkippedCommits.showSkipped(myProject, mySkippedCommits); } @@ -259,6 +275,7 @@ public abstract class GitBaseRebaseProcess { final boolean isStash = getUpdatePolicy() == GitVcsSettings.UpdateChangesPolicy.STASH; HashSet filesToRefresh = isStash ? new HashSet() : null; for (LocalChangeList changeList : myListsCopy) { + LOG.info("GitBaseRebaseProcess.restoreProjectChangesAfterUpdate refreshing files from changelist " + changeList); for (Change c : changeList.getChanges()) { ContentRevision after = c.getAfterRevision(); if (after != null) { @@ -285,6 +302,7 @@ public abstract class GitBaseRebaseProcess { public void run() { for (LocalChangeList changeList : myListsCopy) { final Collection changes = changeList.getChanges(); + LOG.debug("restoreProjectChangesAfterUpdate.invokeAfterUpdate changeList: " + changeList.getName() + " changes: " + changes.size()); if (!changes.isEmpty()) { LOG.debug("After restoring files: moving " + changes.size() + " changes to '" + changeList.getName() + "'"); myChangeManager.moveChangesTo(changeList, changes.toArray(new Change[changes.size()])); @@ -351,12 +369,13 @@ public abstract class GitBaseRebaseProcess { * @return false, if update process needs to be aborted */ private boolean saveProjectChangesBeforeUpdate() { + LOG.info("GitBaseRebaseProcess.saveProjectChangesBeforeUpdate update policy: " + getUpdatePolicy()); if (getUpdatePolicy() == GitVcsSettings.UpdateChangesPolicy.STASH || getUpdatePolicy() == GitVcsSettings.UpdateChangesPolicy.SHELVE) { myStashMessage = makeStashMessage(); myListsCopy = myChangeManager.getChangeListsCopy(); for (LocalChangeList l : myListsCopy) { final Collection changeCollection = l.getChanges(); - LOG.debug("Stashing " + changeCollection.size() + " changes from '" + l.getName() + "'"); + LOG.info("Stashing " + changeCollection.size() + " changes from '" + l.getName() + "'"); for (Change c : changeCollection) { ContentRevision after = c.getAfterRevision(); if (after != null) { @@ -405,7 +424,9 @@ public abstract class GitBaseRebaseProcess { } if (changes.size() > 0) { myProgressIndicator.setText(GitBundle.getString("update.shelving.changes")); + LOG.info("GitBaseRebaseProcess.saveProjectChangesBeforeUpdate shelving changes"); myShelvedChangeList = GitStashUtils.shelveChanges(myProject, myShelveManager, changes, myStashMessage, myExceptions); + LOG.info("GitBaseRebaseProcess.saveProjectChangesBeforeUpdate shelved changes to " + myShelvedChangeList); if (myShelvedChangeList == null) { return false; } diff --git a/plugins/git4idea/src/git4idea/update/GitStashUtils.java b/plugins/git4idea/src/git4idea/update/GitStashUtils.java index 14e13b582b7c..1b66b0b66a4a 100644 --- a/plugins/git4idea/src/git4idea/update/GitStashUtils.java +++ b/plugins/git4idea/src/git4idea/update/GitStashUtils.java @@ -15,6 +15,7 @@ */ package git4idea.update; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.FileStatus; @@ -42,7 +43,11 @@ import org.jetbrains.annotations.Nullable; import javax.swing.event.ChangeEvent; import java.io.File; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; /** * The class contains utilities for creating and removing stashes. @@ -52,6 +57,7 @@ public class GitStashUtils { * The version when quiet stash supported */ private final static GitVersion QUIET_STASH_SUPPORTED = new GitVersion(1, 6, 4, 0); + private static final Logger LOG = Logger.getInstance(GitStashUtils.class.getName()); private GitStashUtils() { } @@ -103,6 +109,7 @@ public class GitStashUtils { final ShelveChangesManager shelveManager, final ChangeListManagerEx changeManager, List exceptions) { + LOG.info("doSystemUnshelve "); // The changes are temporary copied to the first local change list, the next operation will restore them back VirtualFile baseDir = project.getBaseDir(); assert baseDir != null; @@ -126,15 +133,18 @@ public class GitStashUtils { } } LocalFileSystem.getInstance().refreshIoFiles(filesToRefresh); + LOG.info("doSystemUnshelve files refreshed. unshelving in AWT thread."); // Do unshevle UIUtil.invokeAndWaitIfNeeded(new Runnable() { public void run() { GitVFSListener l = GitVcs.getInstance(project).getVFSListener(); l.setEventsSuppressed(true); try { + LOG.info("Unshelving in UI thread. shelvedChangeList: " + shelvedChangeList); shelveManager .unshelveChangeList(shelvedChangeList, shelvedChangeList.getChanges(), shelvedChangeList.getBinaryFiles(), changeManager.getDefaultChangeList(), false); + LOG.info("Deleting change list"); shelveManager.deleteChangeList(shelvedChangeList); } finally { diff --git a/plugins/github/src/META-INF/plugin.xml b/plugins/github/src/META-INF/plugin.xml index c001c3a27454..fef2a86bae91 100644 --- a/plugins/github/src/META-INF/plugin.xml +++ b/plugins/github/src/META-INF/plugin.xml @@ -23,6 +23,9 @@ + + + \ No newline at end of file diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubOpenInBrowserAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubOpenInBrowserAction.java new file mode 100644 index 000000000000..872557ced4ac --- /dev/null +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubOpenInBrowserAction.java @@ -0,0 +1,136 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.github; + +import com.intellij.ide.BrowserUtil; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.IconLoader; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vfs.VirtualFile; +import git4idea.GitRemote; +import git4idea.GitUtil; + +import javax.swing.*; +import java.util.List; + +/** + * Created by IntelliJ IDEA. + * + * @author oleg + * @date 12/10/10 + */ +public class GithubOpenInBrowserAction extends DumbAwareAction { + public static final Icon ICON = IconLoader.getIcon("/icons/github.png"); + private static final Logger LOG = Logger.getInstance(GithubOpenInBrowserAction.class.getName()); + private static final String CANNOT_OPEN_IN_BROWSER = "Cannot open in browser"; + + protected GithubOpenInBrowserAction() { + super("Open in browser", "Open corresponding GitHub link in browser", ICON); + } + + @Override + public void update(final AnActionEvent e) { + final Project project = e.getData(PlatformDataKeys.PROJECT); + final VirtualFile virtualFile = e.getData(PlatformDataKeys.VIRTUAL_FILE); + if (project == null || project.isDefault() || virtualFile == null) { + e.getPresentation().setEnabled(false); + return; + } + if (GithubUtil.getGithubBoundRepository(project) == null){ + e.getPresentation().setEnabled(false); + return; + } + e.getPresentation().setEnabled(true); + } + + @Override + public void actionPerformed(final AnActionEvent e) { + final Project project = e.getData(PlatformDataKeys.PROJECT); + + final VirtualFile[] roots = ProjectRootManager.getInstance(project).getContentRoots(); + if (roots.length == 0) { + Messages.showErrorDialog(project, "Project doesn't have any project roots", CANNOT_OPEN_IN_BROWSER); + return; + } + final VirtualFile root = roots[0]; + // Check if git is already initialized and presence of remote branch + final boolean gitDetected = GitUtil.isUnderGit(root); + if (!gitDetected) { + Messages.showErrorDialog(project, "Cannot find any git repository configured for the project", CANNOT_OPEN_IN_BROWSER); + return; + } + final VirtualFile virtualFile = e.getData(PlatformDataKeys.VIRTUAL_FILE); + final String rootPath = root.getPath(); + final String path = virtualFile.getPath(); + if (!path.startsWith(rootPath)){ + Messages.showErrorDialog(project, "File is not under project root", CANNOT_OPEN_IN_BROWSER); + return; + } + + + try { + // Check that given repository is properly configured git repository + GitRemote githubRemote = null; + final List gitRemotes = GitRemote.list(project, root); + if (gitRemotes.isEmpty()) { + Messages.showErrorDialog(project, "Git repository doesn't have any remotes configured", CANNOT_OPEN_IN_BROWSER); + return; + } + for (GitRemote gitRemote : gitRemotes) { + if (gitRemote.pushUrl().contains("git@github.com")) { + githubRemote = gitRemote; + break; + } + } + if (githubRemote == null) { + Messages.showErrorDialog(project, "Configured own github repository is not found", CANNOT_OPEN_IN_BROWSER); + return; + } + + final String pushUrl = githubRemote.pushUrl(); + final String login = GithubSettings.getInstance().getLogin(); + final int index = pushUrl.lastIndexOf(login); + if (index == -1) { + Messages.showErrorDialog(project, "Github remote repository doesn't seem to be your own repository: " + pushUrl, + CANNOT_OPEN_IN_BROWSER); + return; + } + String repoName = pushUrl.substring(index + login.length() + 1); + if (repoName.endsWith(".git")) { + repoName = repoName.substring(0, repoName.length() - 4); + } + final RepositoryInfo repositoryInfo = GithubUtil.getDetailedRepositoryInfo(project, repoName); + if (repositoryInfo == null) { + Messages + .showErrorDialog(project, "Github repository doesn't seem to be your own repository: " + pushUrl, CANNOT_OPEN_IN_BROWSER); + return; + } + // TODO[oleg] support custom branches here + BrowserUtil.launchBrowser("https://github.com/" + login + "/" + repoName + "/blob/master" + path.substring(rootPath.length())); + + } catch (VcsException e1){ + Messages.showErrorDialog(project, "Error happened during git operation: " + e1.getMessage(), CANNOT_OPEN_IN_BROWSER); + return; + } + + } +} diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java index fe1c677fc9e6..89defbbbe16e 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java @@ -26,7 +26,6 @@ import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; -import git4idea.GitBranch; import git4idea.GitRemote; import git4idea.GitUtil; import git4idea.actions.BasicAction; @@ -45,6 +44,7 @@ import java.util.List; public class GithubRebaseAction extends DumbAwareAction { public static final Icon ICON = IconLoader.getIcon("/icons/github.png"); private static final Logger LOG = Logger.getInstance(GithubRebaseAction.class.getName()); + private static final String CANNOT_PERFORM_GITHUB_REBASE = "Cannot perform github rebase"; public GithubRebaseAction() { super("Rebase my fork", "Rebase your forked repository relative to the origin", ICON); @@ -56,6 +56,10 @@ public class GithubRebaseAction extends DumbAwareAction { e.getPresentation().setEnabled(false); return; } + if (GithubUtil.getGithubBoundRepository(project) == null){ + e.getPresentation().setEnabled(false); + return; + } e.getPresentation().setEnabled(true); } @@ -64,54 +68,29 @@ public class GithubRebaseAction extends DumbAwareAction { final Project project = e.getData(PlatformDataKeys.PROJECT); final VirtualFile[] roots = ProjectRootManager.getInstance(project).getContentRoots(); if (roots.length == 0) { - Messages.showErrorDialog(project, "Project doesn't have any project roots", "Cannot create new GitHub repository"); + Messages.showErrorDialog(project, "Project doesn't have any project roots", CANNOT_PERFORM_GITHUB_REBASE); return; } final VirtualFile root = roots[0]; // Check if git is already initialized and presence of remote branch final boolean gitDetected = GitUtil.isUnderGit(root); if (!gitDetected) { - Messages.showErrorDialog(project, "Cannot find any git repository configured for the project", "Cannot perform github rebase"); + Messages.showErrorDialog(project, "Cannot find any git repository configured for the project", CANNOT_PERFORM_GITHUB_REBASE); return; } try { - // Check current branch - final GitBranch currentBranch = GitBranch.current(project, root); - if (currentBranch == null) { - Messages.showErrorDialog(project, "Cannot find current branch", "Cannot perform github rebase"); - return; - } - if (!"master".equals(currentBranch.getName())) { - Messages.showErrorDialog(project, "Cannot perform rebase with '" + currentBranch.getName() + "' branch.\nPlease switch to master", - "Cannot perform github rebase"); - return; - } - // Check that given repository is properly configured git repository - GitRemote githubRemote = null; + final GitRemote githubRemote = GithubUtil.getGithubBoundRepository(project); final List gitRemotes = GitRemote.list(project, root); - if (gitRemotes.isEmpty()) { - Messages.showErrorDialog(project, "Git repository doesn't have any remotes configured", "Cannot perform github rebase"); - return; - } - for (GitRemote gitRemote : gitRemotes) { - if (gitRemote.pushUrl().contains("git@github.com")) { - githubRemote = gitRemote; - break; - } - } - if (githubRemote == null) { - Messages.showErrorDialog(project, "Configured own github repository is not found", "Cannot perform github rebase"); - return; - } + LOG.assertTrue(githubRemote != null); final String pushUrl = githubRemote.pushUrl(); final String login = GithubSettings.getInstance().getLogin(); final int index = pushUrl.lastIndexOf(login); if (index == -1) { Messages.showErrorDialog(project, "Github remote repository doesn't seem to be your own repository: " + pushUrl, - "Cannot perform github rebase"); + CANNOT_PERFORM_GITHUB_REBASE); return; } String repoName = pushUrl.substring(index + login.length() + 1); @@ -122,12 +101,12 @@ public class GithubRebaseAction extends DumbAwareAction { final RepositoryInfo repositoryInfo = GithubUtil.getDetailedRepositoryInfo(project, repoName); if (repositoryInfo == null) { Messages - .showErrorDialog(project, "Github repository doesn't seem to be your own repository: " + pushUrl, "Cannot perform github rebase"); + .showErrorDialog(project, "Github repository doesn't seem to be your own repository: " + pushUrl, CANNOT_PERFORM_GITHUB_REBASE); return; } if (!repositoryInfo.isFork()) { - Messages.showErrorDialog(project, "Github repository '" + repoName + "' is not a forked one", "Cannot perform github rebase"); + Messages.showErrorDialog(project, "Github repository '" + repoName + "' is not a forked one", CANNOT_PERFORM_GITHUB_REBASE); return; } @@ -161,7 +140,7 @@ public class GithubRebaseAction extends DumbAwareAction { addRemoteHandler.addParameters("add", repoName, parentRepoUrl); addRemoteHandler.run(); if (addRemoteHandler.getExitCode() != 0) { - Messages.showErrorDialog("Failed to add GitHub remote: '" + parentRepoUrl + "'", "Failed to add GitHub remote"); + Messages.showErrorDialog("Failed to add GitHub remote: '" + parentRepoUrl + "'", CANNOT_PERFORM_GITHUB_REBASE); return; } @@ -175,7 +154,7 @@ public class GithubRebaseAction extends DumbAwareAction { action.actionPerformed(actionEvent); } catch (VcsException e1) { - Messages.showErrorDialog(project, "Error happened during git operation: " + e1.getMessage(), "Cannot perform github rebase"); + Messages.showErrorDialog(project, "Error happened during git operation: " + e1.getMessage(), CANNOT_PERFORM_GITHUB_REBASE); return; } } diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubSettings.java b/plugins/github/src/org/jetbrains/plugins/github/GithubSettings.java index 41342b27ba52..80ccdc2542ea 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubSettings.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubSettings.java @@ -40,9 +40,9 @@ public class GithubSettings implements PersistentStateComponent { return null; } final Element element = new Element(GITHUB_SETTINGS_TAG); - element.setAttribute(LOGIN, myLogin); + element.setAttribute(LOGIN, getLogin()); element.setAttribute(PASSWORD, getEncodedPassword()); - element.setAttribute(CLONE_PATH, myClonePath); + element.setAttribute(CLONE_PATH, getClonePath()); return element; } diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubUtil.java b/plugins/github/src/org/jetbrains/plugins/github/GithubUtil.java index b9bda80682de..45c2e8585af4 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubUtil.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubUtil.java @@ -5,9 +5,14 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.Ref; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vfs.VirtualFile; +import git4idea.GitRemote; +import git4idea.GitUtil; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.UsernamePasswordCredentials; @@ -236,4 +241,30 @@ public class GithubUtil { return null; } } + + @Nullable + public static GitRemote getGithubBoundRepository(final Project project){ + final VirtualFile[] roots = ProjectRootManager.getInstance(project).getContentRoots(); + if (roots.length == 0) { + return null; + } + final VirtualFile root = roots[0]; + // Check if git is already initialized and presence of remote branch + final boolean gitDetected = GitUtil.isUnderGit(root); + if (!gitDetected) { + return null; + } + try { + // Check that given repository is properly configured git repository + final List gitRemotes = GitRemote.list(project, root); + for (GitRemote gitRemote : gitRemotes) { + if (gitRemote.pushUrl().contains("git@github.com")) { + return gitRemote; + } + } + } catch (VcsException e){ + // ignore + } + return null; + } } diff --git a/plugins/junit_rt/src/com/intellij/junit3/JUnit3IdeaTestRunner.java b/plugins/junit_rt/src/com/intellij/junit3/JUnit3IdeaTestRunner.java index 8b87d1aa369c..a9cf05ee5cd9 100644 --- a/plugins/junit_rt/src/com/intellij/junit3/JUnit3IdeaTestRunner.java +++ b/plugins/junit_rt/src/com/intellij/junit3/JUnit3IdeaTestRunner.java @@ -62,8 +62,8 @@ public class JUnit3IdeaTestRunner extends TestRunner implements IdeaTestRunner { public void setStreams(SegmentedOutputStream segmentedOut, SegmentedOutputStream segmentedErr) { setPrinter(new TimeSender()); - myRegistry = new JUnit3OutputObjectRegistry(segmentedOut, segmentedErr); - myTestsListener = new TestResultsSender(myRegistry, segmentedErr); + myRegistry = new JUnit3OutputObjectRegistry(segmentedOut); + myTestsListener = new TestResultsSender(myRegistry); } protected TestResult createTestResult() { diff --git a/plugins/junit_rt/src/com/intellij/junit3/JUnit3OutputObjectRegistry.java b/plugins/junit_rt/src/com/intellij/junit3/JUnit3OutputObjectRegistry.java index 0edf7adca7ff..87deb5857916 100644 --- a/plugins/junit_rt/src/com/intellij/junit3/JUnit3OutputObjectRegistry.java +++ b/plugins/junit_rt/src/com/intellij/junit3/JUnit3OutputObjectRegistry.java @@ -28,12 +28,8 @@ import junit.framework.TestCase; import junit.framework.TestSuite; public class JUnit3OutputObjectRegistry extends OutputObjectRegistry { - public JUnit3OutputObjectRegistry(PacketProcessor mainTransport, PacketProcessor auxilaryTransport) { - super(mainTransport, auxilaryTransport); - } - - public JUnit3OutputObjectRegistry(PacketProcessor out) { - super(out); + public JUnit3OutputObjectRegistry(PacketProcessor mainTransport) { + super(mainTransport); } protected int getTestCont(Object test) { diff --git a/plugins/junit_rt/src/com/intellij/junit3/TestResultsSender.java b/plugins/junit_rt/src/com/intellij/junit3/TestResultsSender.java index da85d0d8ddc5..e573a93067c8 100644 --- a/plugins/junit_rt/src/com/intellij/junit3/TestResultsSender.java +++ b/plugins/junit_rt/src/com/intellij/junit3/TestResultsSender.java @@ -18,7 +18,6 @@ package com.intellij.junit3; import com.intellij.rt.execution.junit.*; import com.intellij.rt.execution.junit.segments.OutputObjectRegistry; import com.intellij.rt.execution.junit.segments.Packet; -import com.intellij.rt.execution.junit.segments.PacketProcessor; import com.intellij.rt.execution.junit.states.PoolOfTestStates; import junit.framework.AssertionFailedError; import junit.framework.ComparisonFailure; @@ -27,13 +26,11 @@ import junit.framework.TestListener; public class TestResultsSender implements TestListener { private final OutputObjectRegistry myRegistry; - private final PacketProcessor myErr; private TestMeter myCurrentTestMeter; private Test myCurrentTest; - public TestResultsSender(OutputObjectRegistry packetFactory, PacketProcessor segmentedErr) { + public TestResultsSender(OutputObjectRegistry packetFactory) { myRegistry = packetFactory; - myErr = segmentedErr; } public synchronized void addError(Test test, Throwable throwable) { @@ -93,7 +90,6 @@ public class TestResultsSender implements TestListener { private void switchOutput(Packet switchPacket) { switchPacket.send(); - switchPacket.sendThrough(myErr); } public synchronized void startTest(Test test) { diff --git a/plugins/junit_rt/src/com/intellij/junit3/TreeSender.java b/plugins/junit_rt/src/com/intellij/junit3/TreeSender.java index ba0a54cdb163..caf4791548c9 100644 --- a/plugins/junit_rt/src/com/intellij/junit3/TreeSender.java +++ b/plugins/junit_rt/src/com/intellij/junit3/TreeSender.java @@ -21,16 +21,15 @@ import com.intellij.rt.execution.junit.segments.Packet; import junit.framework.Test; import junit.framework.TestSuite; -import java.util.Enumeration; -import java.util.Vector; +import java.util.*; public class TreeSender { - private static void sendNode(Test test, Packet packet) { + private static void sendNode(Test test, Packet packet, Collection objects) { Vector testCases = getTestCasesOf(test); - packet.addObject(test).addLong(testCases.size()); + packet.addObject(test, objects).addLong(testCases.size()); for (int i = 0; i < testCases.size(); i++) { Test nextTest = (Test)testCases.get(i); - sendNode(nextTest, packet); + sendNode(nextTest, packet, objects); } } @@ -54,7 +53,11 @@ public class TreeSender { public static void sendSuite(OutputObjectRegistry registry, Test suite) { Packet packet = registry.createPacket(); packet.addString(PoolOfDelimiters.TREE_PREFIX); - sendNode(suite, packet); + Collection objects = new ArrayList(); + sendNode(suite, packet, objects); + for (Iterator iterator = objects.iterator(); iterator.hasNext();) { + ((Packet)iterator.next()).send(); + } packet.addString("\n"); packet.send(); } diff --git a/plugins/junit_rt/src/com/intellij/junit4/JUnit4IdeaTestRunner.java b/plugins/junit_rt/src/com/intellij/junit4/JUnit4IdeaTestRunner.java index 7b74dd6413b6..905d43be072d 100644 --- a/plugins/junit_rt/src/com/intellij/junit4/JUnit4IdeaTestRunner.java +++ b/plugins/junit_rt/src/com/intellij/junit4/JUnit4IdeaTestRunner.java @@ -30,26 +30,29 @@ import org.junit.runner.manipulation.Filter; import org.junit.runner.notification.RunListener; import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Iterator; +import java.util.*; /** @noinspection UnusedDeclaration*/ public class JUnit4IdeaTestRunner implements IdeaTestRunner { private RunListener myTestsListener; private OutputObjectRegistry myRegistry; - private static void sendNode(Description test, Packet packet) { + private static void sendNode(Description test, Packet packet, Collection objectPackets) { final ArrayList children = test.getChildren(); - packet.addObject(test).addLong(children.size()); + packet.addObject(test, objectPackets).addLong(children.size()); for (int i = 0; i < children.size(); i++) { - sendNode((Description)children.get(i), packet); + sendNode((Description)children.get(i), packet, objectPackets); } } - public static void sendTree(OutputObjectRegistry registry, Description suite) { + public void sendTree(OutputObjectRegistry registry, Description suite) { Packet packet = registry.createPacket(); packet.addString(PoolOfDelimiters.TREE_PREFIX); - sendNode(suite, packet); + Set objects = new HashSet(); + sendNode(suite, packet, objects); + for (Iterator iterator = objects.iterator(); iterator.hasNext();) { + ((Packet)iterator.next()).send(); + } packet.addString("\n"); packet.send(); } @@ -150,8 +153,8 @@ public class JUnit4IdeaTestRunner implements IdeaTestRunner { public void setStreams(SegmentedOutputStream segmentedOut, SegmentedOutputStream segmentedErr) { - myRegistry = new JUnit4OutputObjectRegistry(segmentedOut, segmentedErr); - myTestsListener = new JUnit4TestResultsSender(myRegistry, segmentedErr); + myRegistry = new JUnit4OutputObjectRegistry(segmentedOut); + myTestsListener = new JUnit4TestResultsSender(myRegistry); } private class TimeSender extends ResultPrinter { diff --git a/plugins/junit_rt/src/com/intellij/junit4/JUnit4OutputObjectRegistry.java b/plugins/junit_rt/src/com/intellij/junit4/JUnit4OutputObjectRegistry.java index 5a1fd67f7efc..d628da9a062b 100644 --- a/plugins/junit_rt/src/com/intellij/junit4/JUnit4OutputObjectRegistry.java +++ b/plugins/junit_rt/src/com/intellij/junit4/JUnit4OutputObjectRegistry.java @@ -27,8 +27,8 @@ import org.junit.runner.Description; public class JUnit4OutputObjectRegistry extends OutputObjectRegistry { - public JUnit4OutputObjectRegistry(PacketProcessor mainTransport, PacketProcessor auxilaryTransport) { - super(mainTransport, auxilaryTransport); + public JUnit4OutputObjectRegistry(PacketProcessor mainTransport) { + super(mainTransport); } protected int getTestCont(Object test) { diff --git a/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java b/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java index 989136a78c7c..af994c2069a4 100644 --- a/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java +++ b/plugins/junit_rt/src/com/intellij/junit4/JUnit4TestResultsSender.java @@ -35,13 +35,11 @@ import java.util.regex.Pattern; public class JUnit4TestResultsSender extends RunListener { private final OutputObjectRegistry myRegistry; - private final PacketProcessor myErr; private Map myCurrentTestMeters = new HashMap(); private Set myCurrentTests = new HashSet(); - public JUnit4TestResultsSender(OutputObjectRegistry packetFactory, PacketProcessor segmentedErr) { + public JUnit4TestResultsSender(OutputObjectRegistry packetFactory) { myRegistry = packetFactory; - myErr = segmentedErr; } public synchronized void testFailure(Failure failure) throws Exception { @@ -139,7 +137,6 @@ public class JUnit4TestResultsSender extends RunListener { private void switchOutput(Packet switchPacket) { switchPacket.send(); - switchPacket.sendThrough(myErr); }