diff --git a/.idea/libraries/commons_logging.xml b/.idea/libraries/commons_logging.xml index b416e063cb58..a9622f732d31 100644 --- a/.idea/libraries/commons_logging.xml +++ b/.idea/libraries/commons_logging.xml @@ -4,6 +4,8 @@ - + + + \ No newline at end of file diff --git a/build/scripts/libLicenses.gant b/build/scripts/libLicenses.gant new file mode 100644 index 000000000000..2502d1b9167a --- /dev/null +++ b/build/scripts/libLicenses.gant @@ -0,0 +1,139 @@ +import org.jetbrains.jps.* + +class LibraryLicense { + String name, libraryName, url, version + String license, licenseUrl +} + +List licensesList = [] +List jetbrainsLibraries = ["tcServiceMessages"] + +binding.setVariable("libraryLicense", {Map args -> + if (args.libraryName == null) { + args.libraryName = args.name; + } + licensesList << new LibraryLicense(args) +}) + +binding.setVariable("jetbrainsLibrary", {String name -> + jetbrainsLibraries << name +}) + +def String getLibraryName(Library lib) { + def name = lib.name + if (name.startsWith("moduleLibrary#")) { + if (lib.classpath.size() != 1) { + project.error("Non-single entry module library $name: $lib.classpath"); + } + String filePath = lib.classpath[0] + return filePath.substring(filePath.lastIndexOf('/')+1) + } + return name +} + +binding.setVariable("checkLibLicenses", { + def libraries = new HashSet() + def lib2Module = new HashMap(); + project.modules.values().each {Module module -> + module.getClasspath(ClasspathKind.PRODUCTION_RUNTIME).each { + if (it instanceof Library) { + lib2Module[it] = module + libraries << it + } + } + } + + def libWithLicenses = licensesList.collect {it.libraryName} as Set + libWithLicenses.addAll(jetbrainsLibraries) + + List withoutLicenses = [] + libraries.each {Library lib -> + def name = getLibraryName(lib) + if (!libWithLicenses.contains(name)) { + withoutLicenses << "$name (used in module ${lib2Module[lib].name})".toString() + } + } + + if (!withoutLicenses.isEmpty()) { + project.warning("Licenses aren't specified for ${withoutLicenses.size()} libraries:") + withoutLicenses.sort(String.CASE_INSENSITIVE_ORDER) + withoutLicenses.each { project.warning(it); } + } +}); + +binding.setVariable("checkLibLicensesAndGenerateTable", {String filePath -> + checkLibLicenses(); + generateLicensesTable(filePath) + notifyArtifactBuilt(filePath) +}) + +binding.setVariable("generateLicensesTable", {String filePath -> + Set modules = project.modules.values().findAll {it["used"] != null} + Set usedLibraries = [] as Set + modules.each { + it.getClasspath(ClasspathKind.PRODUCTION_RUNTIME).each {item -> + if (item instanceof Library) { + usedLibraries << getLibraryName(item) + } + } + } + + def licenses = licensesList.findAll {usedLibraries.contains(it.libraryName) } + List lines = licenses.collect { LibraryLicense lib -> + def name = lib.url != null ? "[$lib.name|$lib.url]" : lib.name + def license = lib.licenseUrl != null ? "[$lib.license|$lib.licenseUrl]" : lib.license + return "|$name| $lib.version|$license|".toString() + } + lines.sort {String.CASE_INSENSITIVE_ORDER} + + FileWriter out = new FileWriter(filePath) + out.println("|| Software || Version || License ||") + lines.each { + out.println(it) + } + out.close() +}) + +libraryLicense(name: "Alloy L&F", libraryName: "alloy.jar", version: "1.4.4", license: "link (company license)", url: "http://www.incors.com/lookandfeel/", licenseUrl: "http://lookandfeel.incors.com/display_licence.php?back=purchase.php&selMenu=Purchase") +libraryLicense(name: "Ant", version: "1.7", license: "Apache 2.0", url: "http://ant.apache.org/", licenseUrl: "http://ant.apache.org/license.html") +libraryLicense(name: "ASM Bytecode Manipulation Framework", libraryName: "asm", version: "3.3", license: "BSD", url: "http://asm.objectweb.org/", licenseUrl: "http://asm.objectweb.org/license.html") +libraryLicense(name: "Axis", libraryName: "axis-1.4", version: "1.4", license: "Apache 2.0", url: "http://ws.apache.org/axis/", licenseUrl: "http://svn.jetbrains.org/idea/Trunk/bundled/WebServices/resources/lib/axis-1.4.0/axis.LICENSE") +libraryLicense(name: "CGLib", libraryName: "CGLIB", version: "2.2", license: "Apache", url: "http://cglib.sourceforge.net/", licenseUrl: "http://www.apache.org/foundation/licence-FAQ.html") +libraryLicense(name: "Apache Commons Codec", libraryName: "commons-codec", version: "1.3", license: "Apache 2.0", url: "http://commons.apache.org/codec/", licenseUrl: "http://commons.apache.org/license.html") +libraryLicense(name: "Apache Commons Collections", libraryName: "commons-collections", version: "3.1", license: "Apache 2.0", url: "http://commons.apache.org/collections/", licenseUrl: "http://commons.apache.org/license.html") +libraryLicense(name: "Apache Commons HTTPClient", libraryName: "http-client-3.1", version: "3.1  (with patch by JetBrains)", license: "Apache 2.0", url: "http://hc.apache.org/httpclient-3.x") +libraryLicense(name: "Apache Commons Lang", libraryName: "commons-lang", version: "2.4", license: "Apache 2.0", url: "http://commons.apache.org/lang/", licenseUrl: "http://commons.apache.org/lang/license.html") +libraryLicense(name: "Apache Commons Logging", libraryName: "commons-logging", version: "1.1.1", license: "Apache 2.0", url: "http://commons.apache.org/logging/", licenseUrl: "http://svn.jetbrains.org/idea/Trunk/bundled/WebServices/resources/lib/axis-1.4.0/commons-logging-1.0.4.LICENSE") +libraryLicense(name: "Automaton", libraryName: "automaton.jar", version: "1.11", license: "BSD", url: "http://www.brics.dk/automaton/", licenseUrl: "http://www.opensource.org/licenses/bsd-license.php") +libraryLicense(name: "DTDParser", version: "1.13", license: "LGPL", url: "http://sourceforge.net/projects/dtdparser/", licenseUrl: "http://www.opensource.org/licenses/lgpl-2.1") +libraryLicense(name: "Ganymed", version: "bundled with SVNKit", license: "BSD", url: "http://www.ganymed.ethz.ch/ssh2/", licenseUrl: "http://www.ganymed.ethz.ch/ssh2/LICENSE.txt") +libraryLicense(name: "Guava", version: "R6", license: "Apache 2.0", url: "http://code.google.com/p/guava-libraries/", licenseUrl: "http://ant.apache.org/license.html") +libraryLicense(name: "Groovy", version: "1.7.3", license: "Apache 2.0", url: "http://groovy.codehaus.org/", licenseUrl: "http://www.apache.org/licenses/LICENSE-2.0.html") +libraryLicense(name: "JavaCVS", version: "no version number available (with patches by JetBrains)", license: "Sun Public License", url: "http://javacvs.netbeans.org/library/", licenseUrl: "http://www.netbeans.org/about/legal/spl.html") +libraryLicense(name: "Jaxen", version: "", license: "modified Apache", url: "http://www.jaxen.org/", licenseUrl: "http://www.jaxen.org/license.html") +libraryLicense(name: "JavaHelp", version: "2.0_02", license: "included as license/javahelp_license.html in IntelliJ IDEA distribution", url: "http://java.sun.com/products/javahelp/") +libraryLicense(name: "JDOM", version: "1.1 (with patches by JetBrains)", license: "modified Apache", url: "http://www.jdom.org/", licenseUrl: "http://www.jdom.org/docs/faq.html#a0030") +libraryLicense(name: "JGoodies Forms", libraryName: "jgoodies-forms", version: "CVS snapshot as of 5 May 2006", license: "BSD ", url: "http://www.jgoodies.com/freeware/forms/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html") +libraryLicense(name: "JNA", libraryName: "jna", version: "3.2.4", license: "LGPL 2.1", url: "https://jna.dev.java.net/", licenseUrl: "http://www.opensource.org/licenses/lgpl-2.1.php") +libraryLicense(name: "JNA", libraryName: "jna.jar", version: "3.2.7", license: "LGPL 2.1", url: "https://jna.dev.java.net/", licenseUrl: "http://www.opensource.org/licenses/lgpl-2.1.php") +libraryLicense(name: "JUnit", libraryName: "JUnit3", version: "3.8.1", license: "CPL 1.0", url: "http://junit.org/") +libraryLicense(name: "JUnit", libraryName: "JUnit4", version: "4.8", license: "CPL 1.0", url: "http://junit.org/") +libraryLicense(name: "Log4j", libraryName: "Log4J", version: "1.2", license: "Apache 2.0", url: "http://logging.apache.org/log4j/1.2/index.html", licenseUrl: "http://logging.apache.org/license.html") +libraryLicense(name: "Maven", version: "2.2.1", license: "Apache 2.0", url: "http://maven.apache.org/", licenseUrl: "http://maven.apache.org/license.html") +libraryLicense(name: "Microba", libraryName: "microba", version: "0.4.2", license: "BSD", url: "http://microba.sourceforge.net/", licenseUrl: "http://microba.sourceforge.net/license.txt") +libraryLicense(name: "NanoXML", version: "2.2.3", license: "zlib/libpng", url: "http://nanoxml.cyberelf.be/", licenseUrl: "http://devkix.com/nanoxml.php") +libraryLicense(name: "Eclipse JDT Core", libraryName: "Eclipse", version: "3.3", license: "CPL 1.0", url: "http://www.eclipse.org/jdt/core/index.php") +libraryLicense(name: "Jakarta ORO", libraryName: "OroMatcher", version: "2.0.8", license: "Apache", url: "http://jakarta.apache.org/oro/", licenseUrl: "http://svn.apache.org/repos/asf/jakarta/oro/trunk/LICENSE") +libraryLicense(name: "PicoContainer", libraryName: "picocontainer", version: "1.2", license: "BSD", url: "http://www.picocontainer.org/", licenseUrl: "http://docs.codehaus.org/display/PICO/License") +libraryLicense(name: "SVNKit", libraryName: "svnkit.jar", version: "SVN version, 1.1 branch as of 1 Oct 2007", license: "link (commercial license)", url: "http://www.svnkit.com/", licenseUrl: "http://svnkit.com/license.html") +libraryLicense(name: "TestNG", version: "5.7 snapshot", license: "Apache 2.0", url: "http://testng.org/doc/", licenseUrl: "http://code.google.com/p/testng/") +libraryLicense(name: "Trilead SSH", libraryName: "trilead-ssh2-build213.jar", version: "build 213", license: "BSD style (see LICENSE.txt in trilead-ssh-build213.jar)", url: "http://www.trilead.com/SSH_Library/") +libraryLicense(name: "Trove4j", version: "1.1 (with patches by JetBrains)", license: "LGPL", url: "http://trove4j.sourceforge.net/", licenseUrl: "http://trove4j.sourceforge.net/html/license.html") +libraryLicense(name: "Velocity", version: "1.3", license: "Apache", url: "http://velocity.apache.org/", licenseUrl: "http://velocity.apache.org/index.html") +libraryLicense(name: "winp", version: "1.14", license: "MIT", url: "http://winp.dev.java.net/", licenseUrl: "https://winp.dev.java.net/license.html") +libraryLicense(name: "Xerces", version: "2.8.1", license: "Apache 2.0", url: "http://xerces.apache.org/xerces2-j/", licenseUrl: "http://xerces.apache.org/xerces2-j/") +libraryLicense(name: "XML Commons (xml-apis.jar, resolver.jar)", version: "", license: "Apache 2.0, W3C Software License , public domain", url: "http://xml.apache.org/commons/", licenseUrl: "http://xml.apache.org/commons/licenses.html") +libraryLicense(name: "XMLBeans", libraryName: "XmlBeans", version: "2.3.0", license: "Apache 2.0", url: "http://xmlbeans.apache.org/", licenseUrl: "http://svn.jetbrains.org/idea/Trunk/bundled/WebServices/resources/lib/xmlbeans-2.3.0/xmlbeans.LICENSE") +libraryLicense(name: "XML-RPC", libraryName: "XmlRPC", version: "2.0", license: "Apache 2.0", url: "http://ws.apache.org/xmlrpc/xmlrpc2/", licenseUrl: "http://ws.apache.org/xmlrpc/xmlrpc2/license.html") +libraryLicense(name: "XStream", version: "1.2.1", license: "BSD", url: "http://xstream.codehaus.org/", licenseUrl: "http://xstream.codehaus.org/license.html") +libraryLicense(name: "YourKit Java Profiler", libraryName: "yjp-controller-api-redist.jar", version: "7.0.2", license: "link (commercial license)", url: "http://yourkit.com/", licenseUrl: "http://www.yourkit.com/purchase/license.html") diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java index 45e9f5bdc89f..a72ed3576209 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/BreakpointWithHighlighter.java @@ -43,6 +43,7 @@ import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; import com.intellij.psi.jsp.JspFile; import com.intellij.ui.classFilter.ClassFilter; import com.intellij.util.StringBuilderSpinAllocator; @@ -444,8 +445,10 @@ public abstract class BreakpointWithHighlighter extends Breakpoint { return false; } final PsiFile psiFile = position.getFile(); + final PsiFile oldFile = getSourcePosition().getFile(); final Document document = PsiDocumentManager.getInstance(getProject()).getDocument(psiFile); - if (document == null) { + final Document oldDocument = PsiDocumentManager.getInstance(getProject()).getDocument(oldFile); + if (document == null || oldDocument == null) { return false; } final RangeHighlighter newHighlighter = createHighlighter(myProject, document, position.getLine()); @@ -458,13 +461,13 @@ public abstract class BreakpointWithHighlighter extends Breakpoint { reload(); if(!isValid()) { - document.getMarkupModel(myProject).removeHighlighter(myHighlighter); + oldDocument.getMarkupModel(myProject).removeHighlighter(myHighlighter); myHighlighter = oldHighlighter; reload(); return false; } - document.getMarkupModel(myProject).removeHighlighter(oldHighlighter); + oldDocument.getMarkupModel(myProject).removeHighlighter(oldHighlighter); DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager().fireBreakpointChanged(this); updateUI(); @@ -666,11 +669,9 @@ public abstract class BreakpointWithHighlighter extends Breakpoint { public GutterDraggableObject getDraggableObject() { return new GutterDraggableObject() { - public void removeSelf() { - } - - public boolean copy(int line) { - return moveTo(SourcePosition.createFromLine(getSourcePosition().getFile(), line)); + public boolean copy(int line, VirtualFile file) { + final PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(file); + return psiFile == null ? false : moveTo(SourcePosition.createFromLine(psiFile, line)); } public Cursor getCursor(int line) { diff --git a/java/java-impl/src/com/intellij/codeInsight/template/macro/SuggestIndexNameMacro.java b/java/java-impl/src/com/intellij/codeInsight/template/macro/SuggestIndexNameMacro.java index 4cdae763a154..0c64857ba37d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/macro/SuggestIndexNameMacro.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/macro/SuggestIndexNameMacro.java @@ -51,7 +51,7 @@ public class SuggestIndexNameMacro implements Macro{ for(char letter = 'i'; letter <= 'z'; letter++){ for (PsiVariable var : vars) { PsiIdentifier identifier = var.getNameIdentifier(); - if (place.equals(identifier)) continue; + if (identifier == null || place.equals(identifier)) continue; if (var instanceof PsiLocalVariable) { PsiElement parent = var.getParent(); if (parent instanceof PsiDeclarationStatement) { diff --git a/lib/src/commons-lang-2.4-sources.jar b/lib/src/commons-lang-2.4-sources.jar new file mode 100644 index 000000000000..7d54d0d197d7 Binary files /dev/null and b/lib/src/commons-lang-2.4-sources.jar differ diff --git a/lib/src/commons-logging-1.1.1-src.zip b/lib/src/commons-logging-1.1.1-src.zip new file mode 100644 index 000000000000..885f130d0ea6 Binary files /dev/null and b/lib/src/commons-logging-1.1.1-src.zip differ diff --git a/platform/lang-api/src/com/intellij/find/FindManager.java b/platform/lang-api/src/com/intellij/find/FindManager.java index f4e85c0496a6..c2866ebe6d94 100644 --- a/platform/lang-api/src/com/intellij/find/FindManager.java +++ b/platform/lang-api/src/com/intellij/find/FindManager.java @@ -108,6 +108,16 @@ public abstract class FindManager { public abstract FindResult findString(@NotNull CharSequence text, int offset, @NotNull FindModel model, @Nullable VirtualFile findContextFile); + public static class MalformedReplacementStringException extends Exception { + public MalformedReplacementStringException(String s) { + super(s); //To change body of overridden methods use File | Settings | File Templates. + } + + public MalformedReplacementStringException(String s, Throwable throwable) { + super(s, throwable); //To change body of overridden methods use File | Settings | File Templates. + } + } + /** * Gets the string to replace with, given the specified found string and find/replace * settings. Supports case-preserving and regular expression replaces. @@ -116,8 +126,9 @@ public abstract class FindManager { * @param model the search and replace settings, including the replace string. * @return the string to replace the specified found string. */ - public abstract String getStringToReplace(@NotNull String foundString, @NotNull FindModel model); - public abstract String getStringToReplace(@NotNull String foundString, @NotNull FindModel model, int startOffset, @NotNull String documentText); + public abstract String getStringToReplace(@NotNull String foundString, @NotNull FindModel model) throws MalformedReplacementStringException; + public abstract String getStringToReplace(@NotNull String foundString, @NotNull FindModel model, + int startOffset, @NotNull String documentText) throws MalformedReplacementStringException; /** * Gets the flag indicating whether the "Find Next" and "Find Previous" actions are diff --git a/platform/lang-api/src/com/intellij/psi/meta/MetaDataRegistrar.java b/platform/lang-api/src/com/intellij/psi/meta/MetaDataRegistrar.java index d86356d4376f..45956f2a929e 100644 --- a/platform/lang-api/src/com/intellij/psi/meta/MetaDataRegistrar.java +++ b/platform/lang-api/src/com/intellij/psi/meta/MetaDataRegistrar.java @@ -22,6 +22,7 @@ import com.intellij.psi.filters.ElementFilter; /** * Provides association for elements matching given filter with metadata class. + * @see MetaDataContributor */ public abstract class MetaDataRegistrar { /** diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java index 7863233390b4..9e2dd837d3d8 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java @@ -886,7 +886,7 @@ public class DocumentationManager { void showHint(final JBPopup hint) { final Lookup lookup = LookupManager.getActiveLookup(myEditor); - if (lookup != null) { + if (lookup != null && lookup.getCurrentItem() != null) { lookup.showItemPopup(hint); return; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/EnterAfterJavadocTagHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/EnterAfterJavadocTagHandler.java index 17792d644ce1..e59da238cd1b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/EnterAfterJavadocTagHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/enter/EnterAfterJavadocTagHandler.java @@ -135,8 +135,12 @@ public class EnterAfterJavadocTagHandler implements EnterHandlerDelegate { continue; } - if (c == '>') { - if (startTagEndOffset < 0) { + if (c == '>' && (startTagEndOffset < 0)) { + if (i > startOffset && text.charAt(i - 1) == '/') { + // Handle situation like '

[offset]' + break; + } + else { startTagEndOffset = i; continue; } diff --git a/platform/lang-impl/src/com/intellij/extapi/psi/StubBasedPsiElementBase.java b/platform/lang-impl/src/com/intellij/extapi/psi/StubBasedPsiElementBase.java index 6fe0c326741a..383a1204608c 100644 --- a/platform/lang-impl/src/com/intellij/extapi/psi/StubBasedPsiElementBase.java +++ b/platform/lang-impl/src/com/intellij/extapi/psi/StubBasedPsiElementBase.java @@ -184,6 +184,9 @@ public class StubBasedPsiElementBase extends ASTDelegateP @NotNull public IStubElementType getElementType() { + if (!(myElementType instanceof IStubElementType)) { + throw new AssertionError("Not a stub type: " + myElementType + " in " + getClass()); + } return (IStubElementType)myElementType; } diff --git a/platform/lang-impl/src/com/intellij/find/FindUtil.java b/platform/lang-impl/src/com/intellij/find/FindUtil.java index 9cb56e56b840..2a3108a8ace5 100644 --- a/platform/lang-impl/src/com/intellij/find/FindUtil.java +++ b/platform/lang-impl/src/com/intellij/find/FindUtil.java @@ -46,6 +46,7 @@ import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; @@ -440,6 +441,21 @@ public class FindUtil { } int startResultOffset = result.getStartOffset(); model.setFromCursor(true); + + int startOffset = result.getStartOffset(); + int endOffset = result.getEndOffset(); + String foundString = document.getCharsSequence().subSequence(startOffset, endOffset).toString(); + String toReplace; + try { + toReplace = findManager.getStringToReplace(foundString, model, startOffset, document.getText()); + } + catch (FindManager.MalformedReplacementStringException e) { + if (!ApplicationManager.getApplication().isUnitTestMode()) { + Messages.showErrorDialog(project, e.getMessage(), FindBundle.message("find.replace.invalid.replacement.string.title")); + } + break; + } + if (toPrompt) { int promptResult = findManager.showPromptDialog(model, FindBundle.message("find.replace.dialog.title")); if (promptResult == FindManager.PromptResult.SKIP) { @@ -455,12 +471,6 @@ public class FindUtil { } } - int startOffset = result.getStartOffset(); - int endOffset = result.getEndOffset(); - String foundString = document.getCharsSequence().subSequence(startOffset, endOffset).toString(); - String toReplace = findManager.getStringToReplace(foundString, model, startOffset, document.getText()); - if (toReplace == null) break; - boolean reallyReplace = toPrompt; TextRange textRange = doReplace(project, document, model, result, toReplace, reallyReplace, rangesToChange); diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java b/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java index 9c5b0286cfed..2bcee259eec9 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindDialog.java @@ -19,6 +19,7 @@ package com.intellij.find.impl; import com.intellij.CommonBundle; import com.intellij.find.FindBundle; +import com.intellij.find.FindManager; import com.intellij.find.FindModel; import com.intellij.find.FindSettings; import com.intellij.ide.util.scopeChooser.ScopeChooserCombo; diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java index e264af03df3c..e2234b3194c0 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java @@ -50,7 +50,6 @@ import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; -import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; @@ -512,7 +511,7 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo return pattern == null ? null : pattern.matcher(text); } - public String getStringToReplace(@NotNull String foundString, @NotNull FindModel model) { + public String getStringToReplace(@NotNull String foundString, @NotNull FindModel model) throws MalformedReplacementStringException { String toReplace = model.getStringToReplace(); if (model.isRegularExpressions()) { return getStringToReplaceByRegexp0(foundString, model); @@ -524,7 +523,8 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo } @Override - public String getStringToReplace(@NotNull String foundString, @NotNull FindModel model, int startOffset, @NotNull String documentText) { + public String getStringToReplace(@NotNull String foundString, @NotNull FindModel model, + int startOffset, @NotNull String documentText) throws MalformedReplacementStringException{ String toReplace = model.getStringToReplace(); if (model.isRegularExpressions()) { return getStringToReplaceByRegexp(model, documentText, startOffset); @@ -535,7 +535,7 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo return toReplace; } - private String getStringToReplaceByRegexp(@NotNull final FindModel model, @NotNull String text, int startOffset) { + private String getStringToReplaceByRegexp(@NotNull final FindModel model, @NotNull String text, int startOffset) throws MalformedReplacementStringException{ Matcher matcher = compileRegExp(model, text); if (model.isForward()){ @@ -563,17 +563,11 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo return replaced.substring(matcher.start()); } catch (Exception e) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - public void run() { - Messages.showErrorDialog(myProject, FindBundle.message("find.replace.invalid.replacement.string", model.getStringToReplace()), - FindBundle.message("find.replace.invalid.replacement.string.title")); - } - }); - return null; + throw new MalformedReplacementStringException(FindBundle.message("find.replace.invalid.replacement.string", model.getStringToReplace()), e); } } - private String getStringToReplaceByRegexp0(String foundString, final FindModel model) { + private String getStringToReplaceByRegexp0(String foundString, final FindModel model) throws MalformedReplacementStringException{ String toFind = model.getStringToFind(); String toReplace = model.getStringToReplace(); Pattern pattern; @@ -594,13 +588,7 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo return matcher.replaceAll(StringUtil.unescapeStringCharacters(toReplace)); } catch (Exception e) { - ApplicationManager.getApplication().invokeLater(new Runnable() { - public void run() { - Messages.showErrorDialog(myProject, FindBundle.message("find.replace.invalid.replacement.string", model.getStringToReplace()), - FindBundle.message("find.replace.invalid.replacement.string.title")); - } - }); - return null; + throw new MalformedReplacementStringException(FindBundle.message("find.replace.invalid.replacement.string", model.getStringToReplace()), e); } } else { diff --git a/platform/lang-impl/src/com/intellij/find/impl/LivePreviewController.java b/platform/lang-impl/src/com/intellij/find/impl/LivePreviewController.java index b8d787f19919..755d6424f69c 100644 --- a/platform/lang-impl/src/com/intellij/find/impl/LivePreviewController.java +++ b/platform/lang-impl/src/com/intellij/find/impl/LivePreviewController.java @@ -113,8 +113,13 @@ public class LivePreviewController implements LivePreview.Delegate, UserActivity if (currentModel != null) { if (currentModel.isReplaceState()) { FindManager findManager = FindManager.getInstance(editor.getProject()); - stringToReplace = findManager.getStringToReplace(foundString, currentModel, - liveOccurrence.getPrimaryRange().getStartOffset(), documentText); + try { + stringToReplace = findManager.getStringToReplace(foundString, currentModel, + liveOccurrence.getPrimaryRange().getStartOffset(), documentText); + } + catch (FindManager.MalformedReplacementStringException e) { + return null; + } if (stringToReplace != null && stringToReplace.isEmpty()) { stringToReplace = EMPTY_STRING_DISPLAY_TEXT; } diff --git a/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java b/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java index d031a7dc5964..08fe256dfad2 100644 --- a/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java +++ b/platform/lang-impl/src/com/intellij/find/replaceInProject/ReplaceInProjectManager.java @@ -341,8 +341,14 @@ public class ReplaceInProjectManager { if (!findResult.isStringFound()) { return; } - String stringToReplace = - findManager.getStringToReplace(foundString.toString(), replaceContext.getFindModel(), textOffset, document.getText()); + String stringToReplace = null; + try { + stringToReplace = + findManager.getStringToReplace(foundString.toString(), replaceContext.getFindModel(), textOffset, document.getText()); + } + catch (FindManager.MalformedReplacementStringException e) { + Messages.showErrorDialog(myProject, e.getMessage(), FindBundle.message("find.replace.invalid.replacement.string.title")); + } if (stringToReplace != null) { document.replaceString(textOffset, textEndOffset, stringToReplace); } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/WeighingNewActionGroup.java b/platform/lang-impl/src/com/intellij/ide/actions/WeighingNewActionGroup.java index b07cf016cb66..37822668bee0 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/WeighingNewActionGroup.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/WeighingNewActionGroup.java @@ -32,6 +32,11 @@ public class WeighingNewActionGroup extends WeighingActionGroup { return myDelegate; } + @Override + public boolean isDumbAware() { + return true; + } + @Override public void update(AnActionEvent e) { super.update(e); diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/text/BlockSupportImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/text/BlockSupportImpl.java index 2395578adf8a..8c49683d476b 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/source/text/BlockSupportImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/source/text/BlockSupportImpl.java @@ -168,6 +168,8 @@ public class BlockSupportImpl extends BlockSupport { FileType fileType = viewProvider.getVirtualFile().getFileType(); final LightVirtualFile lightFile = new LightVirtualFile(fileImpl.getName(), fileType, newFileText, viewProvider.getVirtualFile().getCharset(), fileImpl.getModificationStamp()); + lightFile.setOriginalFile(viewProvider.getVirtualFile()); + final FileViewProvider copy = viewProvider.createCopy(lightFile); final PsiFileImpl newFile = (PsiFileImpl)copy.getPsi(fileImpl.getLanguage()); diff --git a/platform/lang-impl/testSrc/com/intellij/codeInsight/editorActions/enter/EnterAfterJavadocTagHandlerTest.java b/platform/lang-impl/testSrc/com/intellij/codeInsight/editorActions/enter/EnterAfterJavadocTagHandlerTest.java index 85af3f831cd6..f23e85569751 100644 --- a/platform/lang-impl/testSrc/com/intellij/codeInsight/editorActions/enter/EnterAfterJavadocTagHandlerTest.java +++ b/platform/lang-impl/testSrc/com/intellij/codeInsight/editorActions/enter/EnterAfterJavadocTagHandlerTest.java @@ -82,6 +82,12 @@ public class EnterAfterJavadocTagHandlerTest { context = parse(text); assertEmpty(context); } + + @Test + public void emptyTag() { + EnterAfterJavadocTagHandler.Context context = parse("*

"); + assertEmpty(context); + } private static EnterAfterJavadocTagHandler.Context parse(String text) { return parse(text, text.length()); diff --git a/platform/platform-api/src/com/intellij/openapi/editor/markup/GutterDraggableObject.java b/platform/platform-api/src/com/intellij/openapi/editor/markup/GutterDraggableObject.java index 2a7582caf75a..653a9fcdc736 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/markup/GutterDraggableObject.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/markup/GutterDraggableObject.java @@ -15,6 +15,8 @@ */ package com.intellij.openapi.editor.markup; +import com.intellij.openapi.vfs.VirtualFile; + import java.awt.*; /** @@ -22,21 +24,20 @@ import java.awt.*; * a gutter icon which can be dragged and dropped is the breakpoint icon. * * @author ven + * @author Konstantin Bulenkov * @see GutterIconRenderer#getDraggableObject() */ public interface GutterDraggableObject { - /** - * Called when the drag and drop operation is successfully completed. - */ - void removeSelf(); - /** * Called when the icon is dropped over the specified line. * + * * @param line the line over which the icon has been dropped. + * @param file the DnD target file * @return true if the drag and drop operation has completed successfully, false otherwise. + * @since 10.0.3 */ - boolean copy(int line); + boolean copy(int line, VirtualFile file); /** * Returns the cursor to show when the drag is over the specified line. diff --git a/platform/platform-api/src/com/intellij/testFramework/LightVirtualFile.java b/platform/platform-api/src/com/intellij/testFramework/LightVirtualFile.java index 59c97e83ba0e..ce6058e8228b 100644 --- a/platform/platform-api/src/com/intellij/testFramework/LightVirtualFile.java +++ b/platform/platform-api/src/com/intellij/testFramework/LightVirtualFile.java @@ -42,6 +42,7 @@ public class LightVirtualFile extends DeprecatedVirtualFile { private boolean myIsWritable = true; private boolean myValid = true; private Language myLanguage; + private VirtualFile myOriginalFile; public LightVirtualFile() { this(""); @@ -111,6 +112,14 @@ public class LightVirtualFile extends DeprecatedVirtualFile { myContent = content; } + public VirtualFile getOriginalFile() { + return myOriginalFile; + } + + public void setOriginalFile(VirtualFile originalFile) { + myOriginalFile = originalFile; + } + private static class MyVirtualFileSystem extends DeprecatedVirtualFileSystem { @NonNls private static final String PROTOCOL = "mock"; diff --git a/platform/platform-api/src/com/intellij/util/IconUtil.java b/platform/platform-api/src/com/intellij/util/IconUtil.java index 9b4c3a7b13f9..980cf86c3f11 100644 --- a/platform/platform-api/src/com/intellij/util/IconUtil.java +++ b/platform/platform-api/src/com/intellij/util/IconUtil.java @@ -28,9 +28,12 @@ import com.intellij.ui.IconDeferrer; import com.intellij.ui.LayeredIcon; import com.intellij.ui.RowIcon; import com.intellij.util.ui.EmptyIcon; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.awt.*; +import java.awt.image.BufferedImage; public class IconUtil { @@ -178,4 +181,20 @@ public class IconUtil { private static FileIconPatcher[] getPatchers() { return FileIconPatcherHolder.ourPatchers; } + + public static Image toImage(@NotNull Icon icon) { + if (icon instanceof ImageIcon) { + return ((ImageIcon)icon).getImage(); + } + else { + final int w = icon.getIconWidth(); + final int h = icon.getIconHeight(); + final BufferedImage image = GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration().createCompatibleImage(w, h, Color.TRANSLUCENT); + final Graphics2D g = image.createGraphics(); + icon.paintIcon(null, g, 0, 0); + g.dispose(); + return image; + } + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretModelImpl.java index 9d4e8afd9e36..c8a218c3a956 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretModelImpl.java @@ -213,7 +213,7 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener, int newLineNumber = visualCaret.line + lineShift; int newColumnNumber = visualCaret.column + columnShift; - if (desiredX >= 0) { + if (desiredX >= 0 && !ApplicationManager.getApplication().isUnitTestMode()) { newColumnNumber = myEditor.xyToVisualPosition(new Point(desiredX, Math.max(0, newLineNumber) * myEditor.getLineHeight())).column; } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java index 1adc8a45b4d0..1fb75bc9dda8 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java @@ -27,6 +27,7 @@ package com.intellij.openapi.editor.impl; import com.intellij.codeInsight.hint.TooltipController; import com.intellij.codeInsight.hint.TooltipGroup; import com.intellij.ide.IdeEventQueue; +import com.intellij.ide.dnd.*; import com.intellij.ide.ui.UISettings; import com.intellij.ide.ui.customization.CustomActionsSchema; import com.intellij.openapi.actionSystem.*; @@ -43,10 +44,12 @@ import com.intellij.openapi.editor.markup.*; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.ui.popup.Balloon; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.SystemInfo; import com.intellij.ui.HintHint; import com.intellij.ui.awt.RelativePoint; +import com.intellij.util.IconUtil; import com.intellij.util.containers.HashMap; import com.intellij.util.ui.UIUtil; import gnu.trove.TIntArrayList; @@ -59,15 +62,12 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.plaf.ComponentUI; import java.awt.*; -import java.awt.datatransfer.DataFlavor; -import java.awt.datatransfer.Transferable; -import java.awt.dnd.*; import java.awt.event.*; import java.awt.geom.AffineTransform; import java.util.*; import java.util.List; -class EditorGutterComponentImpl extends EditorGutterComponentEx implements MouseListener, MouseMotionListener { +class EditorGutterComponentImpl extends EditorGutterComponentEx implements MouseListener, MouseMotionListener, DnDTarget, DnDSource { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.editor.impl.EditorGutterComponentImpl"); private static final int START_ICON_AREA_WIDTH = 15; private static final int FREE_PAINTERS_AREA_WIDTH = 3; @@ -86,16 +86,14 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse private final Map myProviderToListener = new HashMap(); private static final int GAP_BETWEEN_ANNOTATIONS = 6; private Color myBackgroundColor = null; - private GutterDraggableObject myGutterDraggableObject; private String myLastGutterToolTip = null; private int myLastPreferredHeight = -1; public EditorGutterComponentImpl(EditorImpl editor) { myEditor = editor; if (!ApplicationManager.getApplication().isHeadlessEnvironment()) { - new DropTarget(this, new MyDropTargetListener()); - final DragSource dragSource = DragSource.getDefaultDragSource(); - dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY_OR_MOVE, new MyDragGestureListener()); + DnDManager.getInstance().registerSource(this, this); + DnDManager.getInstance().registerTarget(this, this); } setOpaque(true); } @@ -342,6 +340,57 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse g2.setTransform(old); } + @Override + public boolean update(DnDEvent aEvent) { + aEvent.setDropPossible(true, null); + return false; + } + + @Override + public void drop(DnDEvent aEvent) { + final Object attachedObject = aEvent.getAttachedObject(); + if (attachedObject instanceof GutterIconRenderer) { + final GutterDraggableObject draggableObject = ((GutterIconRenderer)attachedObject).getDraggableObject(); + if (draggableObject != null) { + final int line = convertPointToLineNumber(aEvent.getPoint()); + if (line != -1) { + draggableObject.copy(line, myEditor.getVirtualFile()); + } + } + } + } + + @Override + public void cleanUpOnLeave() { + } + + @Override + public void updateDraggedImage(Image image, Point dropPoint, Point imageOffset) { + } + + @Override + public boolean canStartDragging(DnDAction action, Point dragOrigin) { + return (action == DnDAction.MOVE || action == DnDAction.COPY) && getGutterRenderer(dragOrigin) != null; + } + + @Override + public DnDDragStartBean startDragging(DnDAction action, Point dragOrigin) { + return new DnDDragStartBean(getGutterRenderer(dragOrigin)); + } + + @Override + public Pair createDraggedImage(DnDAction action, Point dragOrigin) { + return new Pair(IconUtil.toImage(getGutterRenderer(dragOrigin).getIcon()), dragOrigin); + } + + @Override + public void dragDropEnd() { + } + + @Override + public void dropActionChanged(int gestureModifiers) { + } + private interface RangeHighlighterProcessor { void process(RangeHighlighter highlighter); } @@ -1264,25 +1313,30 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse TooltipController.getInstance().cancelTooltip(GUTTER_TOOLTIP_GROUP, e, false); } - @Nullable - private GutterIconRenderer getGutterRenderer(final Point p) { - final int ex = convertX((int)p.getX()); + private int convertPointToLineNumber(final Point p) { int line = myEditor.yPositionToLogicalLineNumber((int)p.getY()); - if (line >= myEditor.getDocument().getLineCount()) return null; + if (line >= myEditor.getDocument().getLineCount()) return -1; int startOffset = myEditor.getDocument().getLineStartOffset(line); final FoldRegion region = myEditor.getFoldingModel().getCollapsedRegionAtOffset(startOffset); if (region != null) { line = myEditor.getDocument().getLineNumber(region.getEndOffset()); - if (line >= myEditor.getDocument().getLineCount()) return null; + if (line >= myEditor.getDocument().getLineCount()) return -1; } + return line; + } + @Nullable + private GutterIconRenderer getGutterRenderer(final Point p) { + int line = convertPointToLineNumber(p); + if (line == -1) return null; ArrayList renderers = myLineToGutterRenderers.get(line); if (renderers == null) return null; final GutterIconRenderer[] result = {null}; processIconsRow(line, renderers, new LineGutterIconRendererProcessor() { public void process(int x, int y, GutterIconRenderer renderer) { + final int ex = convertX((int)p.getX()); Icon icon = renderer.getIcon(); if (x <= ex && ex <= x + icon.getIconWidth() && y <= p.getY() && p.getY() <= y + icon.getIconHeight()) { @@ -1310,114 +1364,4 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse } myProviderToListener.clear(); } - - private static final DataFlavor[] FLAVORS; - static { - DataFlavor[] flavors; - try { - final Class aClass = EditorGutterComponentImpl.class; - //noinspection HardCodedStringLiteral - flavors = new DataFlavor[]{new DataFlavor( - DataFlavor.javaJVMLocalObjectMimeType + ";class=" + aClass.getName(), "GutterTransferable", aClass.getClassLoader() - )}; - } - catch (ClassNotFoundException e) { - LOG.error(e); // should not happen - flavors = new DataFlavor[0]; - } - FLAVORS = flavors; - } - - private class MyDragGestureListener implements DragGestureListener { - public void dragGestureRecognized(DragGestureEvent dge) { - if ((dge.getDragAction() & DnDConstants.ACTION_MOVE) == 0) return; - final GutterIconRenderer renderer = getGutterRenderer(dge.getDragOrigin()); - if (renderer != null) { - final GutterDraggableObject draggableObject = renderer.getDraggableObject(); - if (draggableObject != null) { - try { - myGutterDraggableObject = draggableObject; - final MyDragSourceListener dragSourceListener = new MyDragSourceListener(); - dge.startDrag(DragSource.DefaultMoveNoDrop, new Transferable () { - public DataFlavor[] getTransferDataFlavors() { - return FLAVORS; - } - - public boolean isDataFlavorSupported(DataFlavor flavor) { - DataFlavor[] flavors = getTransferDataFlavors(); - for (DataFlavor flavor1 : flavors) { - if (flavor.equals(flavor1)) { - return true; - } - } - return false; - } - - public Object getTransferData(DataFlavor flavor) { - return null; - } - }, dragSourceListener); - } - catch (InvalidDnDOperationException e) { - // OK, can't dnd - } - } - - } - } - } - - private class MyDragSourceListener extends DragSourceAdapter { - public void dragEnter(DragSourceDragEvent e) { - updateCursor(e); - } - - public void dragOver(DragSourceDragEvent e) { - updateCursor(e); - } - - public void dropActionChanged(DragSourceDragEvent e) { - e.getDragSourceContext().setCursor(null);//setCursor (e.getDragSourceContext()); - } - - private void updateCursor(final DragSourceDragEvent e) { - final DragSourceContext context = e.getDragSourceContext(); - final Point screenPoint = e.getLocation(); - if (screenPoint != null) { - final Point gutterPoint = new Point(screenPoint); - SwingUtilities.convertPointFromScreen(gutterPoint, EditorGutterComponentImpl.this); - if (contains(gutterPoint)){ - final Point editorPoint = new Point(screenPoint); - SwingUtilities.convertPointFromScreen(editorPoint, myEditor.getContentComponent()); - int line = myEditor.yPositionToLogicalLineNumber((int)editorPoint.getY()); - final Cursor cursor = myGutterDraggableObject.getCursor(line); - context.setCursor(cursor); - return; - } - } - context.setCursor(null); - } - - public void dragDropEnd(DragSourceDropEvent e) { - if (!e.getDropSuccess()) return; - - if (e.getDropAction() == DnDConstants.ACTION_MOVE) { - myGutterDraggableObject.removeSelf(); - } - } - } - - private class MyDropTargetListener extends DropTargetAdapter { - public void drop(DropTargetDropEvent e) { - if (myGutterDraggableObject != null) { - int dropAction = e.getDropAction(); - if ((dropAction & DnDConstants.ACTION_MOVE) != 0) { - int line = myEditor.yPositionToLogicalLineNumber((int)e.getLocation().getY()); - e.dropComplete(myGutterDraggableObject.copy(line)); - return; - } - } - e.rejectDrop(); - } - } } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java index b7f931f603d6..7320e895d910 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XLineBreakpointImpl.java @@ -270,8 +270,7 @@ public class XLineBreakpointImpl

extends XBreak } } - private boolean canMoveTo(int line) { - final VirtualFile file = getFile(); + private boolean canMoveTo(int line, VirtualFile file) { return file != null && myType.canPutAt(file, line, getProject()); } @@ -389,11 +388,9 @@ public class XLineBreakpointImpl

extends XBreak @Override public GutterDraggableObject getDraggableObject() { return new GutterDraggableObject() { - public void removeSelf() { - } - - public boolean copy(int line) { - if (canMoveTo(line)) { + public boolean copy(int line, VirtualFile file) { + if (canMoveTo(line, file)) { + setFileUrl(file.getUrl()); setLine(line); return true; } @@ -401,7 +398,7 @@ public class XLineBreakpointImpl

extends XBreak } public Cursor getCursor(int line) { - return canMoveTo(line) ? DragSource.DefaultMoveDrop : DragSource.DefaultMoveNoDrop; + return canMoveTo(line, getFile()) ? DragSource.DefaultMoveDrop : DragSource.DefaultMoveNoDrop; } }; } diff --git a/plugins/android/resources/fileTemplates/j2ee/Application.java.ft b/plugins/android/resources/fileTemplates/j2ee/Application.java.ft new file mode 100644 index 000000000000..336051a028f2 --- /dev/null +++ b/plugins/android/resources/fileTemplates/j2ee/Application.java.ft @@ -0,0 +1,7 @@ +package ${PACKAGE_NAME}; + +import android.app.Application; + +#parse("File Header.java") +public class ${NAME} extends Application { +} diff --git a/plugins/android/resources/fileTemplates/j2ee/Application.java.html b/plugins/android/resources/fileTemplates/j2ee/Application.java.html new file mode 100644 index 000000000000..09a7bfbff9e3 --- /dev/null +++ b/plugins/android/resources/fileTemplates/j2ee/Application.java.html @@ -0,0 +1,5 @@ + + +

This is a built-in file template used to create custom Application class in Android applications.

+ + \ No newline at end of file diff --git a/plugins/android/resources/messages/AndroidBundle.properties b/plugins/android/resources/messages/AndroidBundle.properties index e98186580071..6a224277a061 100644 --- a/plugins/android/resources/messages/AndroidBundle.properties +++ b/plugins/android/resources/messages/AndroidBundle.properties @@ -231,4 +231,5 @@ android.compilation.error.apt.gen.not.specified=AAPT destination directory not s android.compilation.error.aidl.gen.not.specified=AIDL destination directory not specified for module {0} android.compilation.error.apk.path.not.specified=Final APK path not specified for module {0} android.restart.logcat.action.text=Restart -android.restart.logcat.action.description=Restart logging \ No newline at end of file +android.restart.logcat.action.description=Restart logging +android.new.component.dialog.application.item=Application \ No newline at end of file diff --git a/plugins/android/src/org/jetbrains/android/AndroidFileTemplateProvider.java b/plugins/android/src/org/jetbrains/android/AndroidFileTemplateProvider.java index 660aa42babc8..b35681b54376 100644 --- a/plugins/android/src/org/jetbrains/android/AndroidFileTemplateProvider.java +++ b/plugins/android/src/org/jetbrains/android/AndroidFileTemplateProvider.java @@ -42,6 +42,7 @@ public class AndroidFileTemplateProvider implements FileTemplateGroupDescriptorF @NonNls public static final String RESOURCE_FILE_TEMPLATE = "resourceFile.xml"; @NonNls public static final String LAYOUT_RESOURCE_FILE_TEMPLATE = "layoutResourceFile.xml"; @NonNls public static final String ACTIVITY = "Activity.java"; + @NonNls public static final String APPLICATION = "Application.java"; @NonNls public static final String SERVICE = "Service.java"; @NonNls public static final String BROADCAST_RECEIVER = "Broadcast Receiver.java"; @@ -52,6 +53,7 @@ public class AndroidFileTemplateProvider implements FileTemplateGroupDescriptorF group.addTemplate(new FileTemplateDescriptor(RESOURCE_FILE_TEMPLATE, StdFileTypes.XML.getIcon())); group.addTemplate(new FileTemplateDescriptor(LAYOUT_RESOURCE_FILE_TEMPLATE, StdFileTypes.XML.getIcon())); group.addTemplate(new FileTemplateDescriptor(ACTIVITY, StdFileTypes.JAVA.getIcon())); + group.addTemplate(new FileTemplateDescriptor(APPLICATION, StdFileTypes.JAVA.getIcon())); group.addTemplate(new FileTemplateDescriptor(SERVICE, StdFileTypes.JAVA.getIcon())); group.addTemplate(new FileTemplateDescriptor(BROADCAST_RECEIVER, StdFileTypes.JAVA.getIcon())); group.addTemplate(new FileTemplateDescriptor(REMOTE_INTERFACE_TEMPLATE, AndroidIdlFileType.ourFileType.getIcon())); diff --git a/plugins/android/src/org/jetbrains/android/actions/NewAndroidComponentAction.java b/plugins/android/src/org/jetbrains/android/actions/NewAndroidComponentAction.java index a09b41c039f4..bba3e11c914e 100644 --- a/plugins/android/src/org/jetbrains/android/actions/NewAndroidComponentAction.java +++ b/plugins/android/src/org/jetbrains/android/actions/NewAndroidComponentAction.java @@ -18,7 +18,6 @@ package org.jetbrains.android.actions; import com.intellij.ide.IdeView; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.module.Module; -import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.psi.JavaDirectoryService; import com.intellij.psi.PsiDirectory; @@ -64,12 +63,14 @@ public class NewAndroidComponentAction extends AnAction { return; } - final Project project = PlatformDataKeys.PROJECT.getData(dataContext); + final Module module = LangDataKeys.MODULE.getData(dataContext); + + if (module == null) return; final PsiDirectory dir = view.getOrChooseDirectory(); if (dir == null) return; - NewAndroidComponentDialog dialog = new NewAndroidComponentDialog(project, dir); + NewAndroidComponentDialog dialog = new NewAndroidComponentDialog(module, dir); dialog.show(); if (dialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) { return; diff --git a/plugins/android/src/org/jetbrains/android/actions/NewAndroidComponentDialog.java b/plugins/android/src/org/jetbrains/android/actions/NewAndroidComponentDialog.java index 9e9ff9cf8e7d..aa3cbd09b151 100644 --- a/plugins/android/src/org/jetbrains/android/actions/NewAndroidComponentDialog.java +++ b/plugins/android/src/org/jetbrains/android/actions/NewAndroidComponentDialog.java @@ -18,16 +18,19 @@ package org.jetbrains.android.actions; import com.intellij.CommonBundle; import com.intellij.ide.actions.ElementCreator; import com.intellij.ide.actions.TemplateKindCombo; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.util.Computable; import com.intellij.psi.*; +import com.intellij.psi.search.searches.ClassInheritorsSearch; import com.intellij.util.Icons; import com.intellij.util.IncorrectOperationException; import org.jetbrains.android.AndroidFileTemplateProvider; -import org.jetbrains.android.dom.manifest.*; import org.jetbrains.android.dom.manifest.Action; +import org.jetbrains.android.dom.manifest.*; import org.jetbrains.android.dom.resources.ResourceValue; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.util.AndroidBundle; @@ -55,12 +58,18 @@ public class NewAndroidComponentDialog extends DialogWrapper { private PsiElement[] myCreatedElements; - protected NewAndroidComponentDialog(final Project project, final PsiDirectory directory) { - super(project); + protected NewAndroidComponentDialog(@NotNull final Module module, final PsiDirectory directory) { + super(module.getProject()); myKindLabel.setLabelFor(myKindCombo); myKindCombo.registerUpDownHint(myNameField); myUpDownHint.setIcon(Icons.UP_DOWN_ARROWS); myKindCombo.addItem(AndroidBundle.message("android.new.component.dialog.activity.item"), null, AndroidFileTemplateProvider.ACTIVITY); + + if (!containsCustomApplicationClass(module)) { + myKindCombo.addItem(AndroidBundle.message("android.new.component.dialog.application.item"), null, + AndroidFileTemplateProvider.APPLICATION); + } + myKindCombo.addItem(AndroidBundle.message("android.new.component.dialog.service.item"), null, AndroidFileTemplateProvider.SERVICE); myKindCombo.addItem(AndroidBundle.message("android.new.component.dialog.broadcast.receiver.item"), null, AndroidFileTemplateProvider.BROADCAST_RECEIVER); @@ -68,7 +77,7 @@ public class NewAndroidComponentDialog extends DialogWrapper { AndroidFileTemplateProvider.REMOTE_INTERFACE_TEMPLATE); init(); setTitle(AndroidBundle.message("android.new.component.action.command.name")); - myCreator = new ElementCreator(project, CommonBundle.getErrorTitle()) { + myCreator = new ElementCreator(module.getProject(), CommonBundle.getErrorTitle()) { @Override protected void checkBeforeCreate(String newName) throws IncorrectOperationException { JavaDirectoryService.getInstance().checkCreateClass(directory, newName); @@ -76,7 +85,7 @@ public class NewAndroidComponentDialog extends DialogWrapper { @Override protected PsiElement[] create(String newName) throws Exception { - final PsiElement element = NewAndroidComponentDialog.this.create(newName, directory, project); + final PsiElement element = NewAndroidComponentDialog.this.create(newName, directory, module.getProject()); if (element != null) { return new PsiElement[]{element}; } @@ -93,11 +102,23 @@ public class NewAndroidComponentDialog extends DialogWrapper { public void actionPerformed(ActionEvent e) { String selected = myKindCombo.getSelectedName(); myMarkAsStartupActivityCheckBox.setEnabled(AndroidFileTemplateProvider.ACTIVITY.equals(selected)); - myLabelField.setEnabled(!AndroidFileTemplateProvider.REMOTE_INTERFACE_TEMPLATE.equals(selected)); + myLabelField.setEnabled(!AndroidFileTemplateProvider.REMOTE_INTERFACE_TEMPLATE.equals(selected) && + !AndroidFileTemplateProvider.APPLICATION.equals(selected)); } }); } + private static boolean containsCustomApplicationClass(@NotNull final Module module) { + final JavaPsiFacade facade = JavaPsiFacade.getInstance(module.getProject()); + PsiClass applicationClass = ApplicationManager.getApplication().runReadAction(new Computable() { + @Nullable + public PsiClass compute() { + return facade.findClass(AndroidUtils.APPLICATION_CLASS_NAME, module.getModuleWithDependenciesAndLibrariesScope(false)); + } + }); + return applicationClass != null && ClassInheritorsSearch.search(applicationClass, module.getModuleScope(), true).findFirst() != null; + } + @Nullable private PsiElement create(String newName, PsiDirectory directory, Project project) throws Exception { return doCreate(myKindCombo.getSelectedName(), directory, project, newName, myLabelField.getText(), @@ -175,6 +196,9 @@ public class NewAndroidComponentDialog extends DialogWrapper { receiver.getReceiverClass().setValue(aClass); return receiver; } + else if (AndroidFileTemplateProvider.APPLICATION.equals(templateName)) { + application.getName().setValue(aClass); + } return null; } diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetConfiguration.java b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetConfiguration.java index 5c5369ad61a4..25ba1e9fb203 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetConfiguration.java +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetConfiguration.java @@ -77,15 +77,19 @@ public class AndroidFacetConfiguration implements FacetConfiguration { private AndroidFacet myFacet = null; public void init(@NotNull Module module, @NotNull VirtualFile contentRoot) { + init(module, contentRoot.getPath()); + } + + public void init(@NotNull Module module, @NotNull String baseDirectoryPath) { String moduleDirPath = AndroidRootUtil.getModuleDirPath(module); if (moduleDirPath == null) { return; } - if (moduleDirPath.equals(contentRoot.getPath())) { + if (moduleDirPath.equals(baseDirectoryPath)) { return; } - String s = FileUtil.getRelativePath(moduleDirPath, contentRoot.getPath(), '/'); + String s = FileUtil.getRelativePath(moduleDirPath, baseDirectoryPath, '/'); GEN_FOLDER_RELATIVE_PATH_APT = '/' + s + GEN_FOLDER_RELATIVE_PATH_APT; GEN_FOLDER_RELATIVE_PATH_AIDL = '/' + s + GEN_FOLDER_RELATIVE_PATH_AIDL; diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java index 5afed5173670..99ef1974899a 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java @@ -171,6 +171,10 @@ public class AndroidFacetEditorTab extends FacetEditorTab { public void actionPerformed(ActionEvent e) { AndroidFacetConfiguration configuration = new AndroidFacetConfiguration(); Module module = myContext.getModule(); + VirtualFile[] contentRoots = ModuleRootManager.getInstance(module).getContentRoots(); + if (contentRoots.length == 1) { + configuration.init(module, contentRoots[0]); + } if (AndroidMavenUtil.isMavenizedModule(module)) { AndroidMavenProvider mavenProvider = AndroidMavenUtil.getMavenProvider(); if (mavenProvider != null) { diff --git a/plugins/android/src/org/jetbrains/android/maven/AndroidFacetImporter.java b/plugins/android/src/org/jetbrains/android/maven/AndroidFacetImporter.java index 8149f074ff51..9e9b93a75adc 100644 --- a/plugins/android/src/org/jetbrains/android/maven/AndroidFacetImporter.java +++ b/plugins/android/src/org/jetbrains/android/maven/AndroidFacetImporter.java @@ -76,6 +76,8 @@ public class AndroidFacetImporter extends FacetImporter + diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java index 6cb51c691072..bc27bb0833ba 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java @@ -1,5 +1,9 @@ package org.jetbrains.plugins.github; +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationDisplayType; +import com.intellij.notification.NotificationType; +import com.intellij.notification.Notifications; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.ApplicationManager; @@ -12,6 +16,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.IconLoader; +import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.Ref; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.ChangeListManager; @@ -113,7 +118,7 @@ public class GithubShareAction extends DumbAwareAction { try { LOG.info("Creating GitHub repository"); GithubUtil.doREST(settings.getHost(), settings.getLogin(), settings.getPassword(), - "/repos/create?name=" + name + "&description=" + description + "&public=" + (isPrivate ? "0" : "1"), true); + "/repos/create?name=" + name + "&public=" + (isPrivate ? "0" : "1") + "&description=" + JDOMUtil.escapeText(description, true, true), true); LOG.info("Successfully created GitHub repository"); } catch (final Exception e1) { @@ -121,6 +126,8 @@ public class GithubShareAction extends DumbAwareAction { return; } bindToGithub(project, root, gitDetected, settings.getLogin(), name); + Notifications.Bus.notify(new Notification("github", "Success", "Successfully created project ''" + name + "'' on github", + NotificationType.INFORMATION), NotificationDisplayType.BALLOON_ONLY, null); } private void bindToGithub(final Project project, final VirtualFile root, final boolean gitDetected, final String login, final String name) { diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubUtil.java b/plugins/github/src/org/jetbrains/plugins/github/GithubUtil.java index 030bdb249568..9cac56ee2348 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubUtil.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubUtil.java @@ -6,7 +6,6 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; -import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; @@ -94,7 +93,7 @@ public class GithubUtil { public static HttpMethod doREST(final String url, final String login, final String password, final String request, final boolean post) throws Exception { final HttpClient client = getHttpClient(login, password); client.getParams().setContentCharset("UTF-8"); - final String uri = JDOMUtil.escapeText("https://" + getHostByUrl(url) + API_URL + request, true, true); + final String uri = "https://" + getHostByUrl(url) + API_URL + request; final HttpMethod method = post ? new PostMethod(uri) : new GetMethod(uri); client.executeMethod(method); return method; @@ -171,7 +170,7 @@ public class GithubUtil { } final Element plan = element.getChild("plan"); assert plan != null : "Authentification failed"; - final String privateRepos = plan.getChildText("private_repos"); + final String privateRepos = plan.getChildText("private-repos"); return privateRepos != null && Integer.valueOf(privateRepos) > 0; } catch (Exception e) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyElementTypes.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyElementTypes.java index 6fb3bafe4c6b..3d6b5fae30e2 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyElementTypes.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/parser/GroovyElementTypes.java @@ -16,6 +16,7 @@ package org.jetbrains.plugins.groovy.lang.parser; +import com.intellij.lang.ASTNode; import com.intellij.psi.stubs.*; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; @@ -356,7 +357,17 @@ public interface GroovyElementTypes extends GroovyTokenTypes, GroovyDocElementTy GroovyElementType SYNCHRONIZED_STATEMENT = new GroovyElementType("synchronized block statement"); GroovyElementType CLASS_INITIALIZER = new GroovyElementType("static compound statement"); - GroovyElementType VARIABLE_DEFINITION_ERROR = new GroovyElementType("variable definitions with errors"); + EmptyStubElementType VARIABLE_DEFINITION_ERROR = new EmptyStubElementType("variable definitions with errors", GroovyFileType.GROOVY_LANGUAGE) { + @Override + public boolean shouldCreateStub(ASTNode node) { + return false; + } + + @Override + public GrVariableDeclaration createPsi(EmptyStub stub) { + throw new UnsupportedOperationException("Not implemented"); + } + }; EmptyStubElementType VARIABLE_DEFINITION = new EmptyStubElementType("variable definitions", GroovyFileType.GROOVY_LANGUAGE) { @Override @@ -391,4 +402,4 @@ public interface GroovyElementTypes extends GroovyTokenTypes, GroovyDocElementTy TokenSet VARIABLES = TokenSet.create(VARIABLE, FIELD); TokenSet TYPE_ELEMENTS = TokenSet.create(CLASS_TYPE_ELEMENT, ARRAY_TYPE, BUILT_IN_TYPE, TYPE_ARGUMENT); -} \ No newline at end of file +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java index daa91c385429..7452788e63e5 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/CompleteReferenceExpression.java @@ -148,6 +148,11 @@ public class CompleteReferenceExpression { } } + @NotNull + public static LookupElementBuilder createPropertyLookupElement(@NotNull String name, @NotNull PsiType type) { + return LookupElementBuilder.create(name).setIcon(GroovyIcons.PROPERTY).setTypeText(type.getPresentableText()); + } + @Nullable public static LookupElementBuilder createPropertyLookupElement(@NotNull PsiMethod accessor, @Nullable GroovyResolveResult resolveResult) { String propName; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java index 77e62a6a469c..893daddfc483 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java @@ -53,7 +53,7 @@ public class GrStubFileElementType extends IStubFileElementType { @Override public int getStubVersion() { - return super.getStubVersion() + 9; + return super.getStubVersion() + 10; } public String getExternalId() { diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java index abf11cd65bb9..60b284be13b2 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.java @@ -334,4 +334,8 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase { public void testMethodImplementedByDelegate() { doTest(); } + + public void testTestMarkupStubs() { + doTest(); + } } \ No newline at end of file diff --git a/plugins/groovy/testdata/highlighting/TestMarkupStubs.groovy b/plugins/groovy/testdata/highlighting/TestMarkupStubs.groovy new file mode 100644 index 000000000000..8175bc3a4981 --- /dev/null +++ b/plugins/groovy/testdata/highlighting/TestMarkupStubs.groovy @@ -0,0 +1,7 @@ +abstract class X { + abstract def foo<caret>(String s, int a) + + def foo(String s) { + return foo(s, 5); + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationManager.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationManager.java index 74846f450921..a683ee9a8aa1 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationManager.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnAuthenticationManager.java @@ -56,6 +56,9 @@ import java.util.*; public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager implements SvnAuthenticationListener { // while Mac storage not working for IDEA, we use this key to check whether to prompt abt plaintext or just store private static final Logger LOG = Logger.getInstance(SvnAuthenticationManager.class.getName()); + public static final String SVN_SSH = "svn+ssh"; + public static final String HTTP = "http"; + public static final String HTTPS = "https"; private final Project myProject; private File myConfigDirectory; private PersistentAuthenticationProviderProxy myPersistentAuthenticationProviderProxy; @@ -400,7 +403,7 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im @Override public int getReadTimeout(final SVNRepository repository) { String protocol = repository.getLocation().getProtocol(); - if ("http".equals(protocol) || "https".equals(protocol)) { + if (HTTP.equals(protocol) || HTTPS.equals(protocol)) { String host = repository.getLocation().getHost(); String timeout = getServersPropertyIdea(host, "http-timeout"); if (timeout != null) { @@ -412,9 +415,25 @@ public class SvnAuthenticationManager extends DefaultSVNAuthenticationManager im } return DEFAULT_READ_TIMEOUT; } + if (SVN_SSH.equals(protocol)) { + return (int) myConfig.mySSHReadTimeout; + } return 0; } + @Override + public int getConnectTimeout(SVNRepository repository) { + String protocol = repository.getLocation().getProtocol(); + if (SVN_SSH.equals(protocol)) { + return (int) myConfig.mySSHConnectionTimeout; + } + final int connectTimeout = super.getConnectTimeout(repository); + if ((HTTP.equals(protocol) || HTTPS.equals(protocol)) && (connectTimeout <= 0)) { + return DEFAULT_READ_TIMEOUT; + } + return connectTimeout; + } + // taken from default manager as is private String getServersPropertyIdea(String host, final String name) { final SVNCompositeConfigFile serversFile = getHostOptionsProvider().getServersFile(); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.form b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.form index da771de23f12..d10d3b6dcc5b 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.form +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.form @@ -1,16 +1,16 @@
- + - + - + @@ -188,6 +188,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.java index abf476929546..f0eb2258165a 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfigurable.java @@ -58,6 +58,8 @@ public class SvnConfigurable implements Configurable { private JCheckBox myShowMergeSourceInAnnotate; private JSpinner myNumRevsInAnnotations; private JCheckBox myMaximumNumberOfRevisionsCheckBox; + private JSpinner mySSHConnectionTimeout; + private JSpinner mySSHReadTimeout; @NonNls private static final String HELP_ID = "project.propSubversion"; @@ -128,7 +130,7 @@ public class SvnConfigurable implements Configurable { } }); myNumRevsInAnnotations.setEnabled(myMaximumNumberOfRevisionsCheckBox.isSelected()); - } + } private FileChooserDescriptor createFileDescriptor() { final FileChooserDescriptor descriptor = new FileChooserDescriptor(false, true, false, false, false, false); @@ -192,6 +194,12 @@ public class SvnConfigurable implements Configurable { return true; } } + if (configuration.mySSHConnectionTimeout != ((SpinnerNumberModel) mySSHConnectionTimeout.getModel()).getNumber().longValue()) { + return true; + } + if (configuration.mySSHReadTimeout != ((SpinnerNumberModel) mySSHReadTimeout.getModel()).getNumber().longValue()) { + return true; + } return !configuration.getConfigurationDirectory().equals(myConfigurationDirectoryText.getText().trim()); } @@ -213,6 +221,8 @@ public class SvnConfigurable implements Configurable { } else { configuration.setMaxAnnotateRevisions(((SpinnerNumberModel) myNumRevsInAnnotations.getModel()).getNumber().intValue()); } + configuration.mySSHConnectionTimeout = ((SpinnerNumberModel) mySSHConnectionTimeout.getModel()).getNumber().longValue() * 1000; + configuration.mySSHReadTimeout = ((SpinnerNumberModel) mySSHReadTimeout.getModel()).getNumber().longValue() * 1000; } public void reset() { @@ -243,6 +253,8 @@ public class SvnConfigurable implements Configurable { myNumRevsInAnnotations.setValue(annotateRevisions); } myNumRevsInAnnotations.setEnabled(myMaximumNumberOfRevisionsCheckBox.isSelected()); + mySSHConnectionTimeout.setValue(configuration.mySSHConnectionTimeout / 1000); + mySSHReadTimeout.setValue(configuration.mySSHReadTimeout / 1000); } public void disposeUIResources() { @@ -264,6 +276,12 @@ public class SvnConfigurable implements Configurable { int value = configuration.getMaxAnnotateRevisions(); value = (value == -1) ? SvnConfiguration.ourMaxAnnotateRevisionsDefault : value; myNumRevsInAnnotations = new JSpinner(new SpinnerNumberModel(value, 10, 100000, 100)); + + final int maximum = 30 * 60 * 1000; + final long connection = configuration.mySSHConnectionTimeout <= maximum ? configuration.mySSHConnectionTimeout : maximum; + final long read = configuration.mySSHReadTimeout <= maximum ? configuration.mySSHReadTimeout : maximum; + mySSHConnectionTimeout = new JSpinner(new SpinnerNumberModel(connection / 1000, 0, maximum, 10)); + mySSHReadTimeout = new JSpinner(new SpinnerNumberModel(read / 1000, 0, maximum, 10)); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java index 7c0333e99354..b334ae07c122 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java @@ -28,6 +28,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vcs.annotate.AnnotationListener; +import com.intellij.util.io.DataExternalizer; import org.jdom.Attribute; import org.jdom.DataConversionException; import org.jdom.Element; @@ -80,6 +81,9 @@ public class SvnConfiguration implements ProjectComponent, JDOMExternalizable { private String myUpgradeMode; private SvnSupportOptions mySupportOptions; private int myMaxAnnotateRevisions = ourMaxAnnotateRevisionsDefault; + private final static long DEFAULT_SSH_TIMEOUT = 30 * 1000; + public long mySSHConnectionTimeout = DEFAULT_SSH_TIMEOUT; + public long mySSHReadTimeout = DEFAULT_SSH_TIMEOUT; public static final AuthStorage RUNTIME_AUTH_CACHE = new AuthStorage(); public String LAST_MERGED_REVISION = null;