Merge branch 'master' of git.labs.intellij.net:idea/community
authorDmitry Boulytchev (dboulytchev@gmail.com) <gjhjctyjr>
Wed, 1 Feb 2012 21:24:44 +0000 (01:24 +0400)
committerDmitry Boulytchev (dboulytchev@gmail.com) <gjhjctyjr>
Wed, 1 Feb 2012 21:24:44 +0000 (01:24 +0400)
37 files changed:
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JdkComboBox.java
java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java
java/java-impl/src/com/intellij/codeInsight/completion/DefaultInsertHandler.java
java/java-impl/src/com/intellij/codeInsight/completion/Java15CompletionData.java
java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java
java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionData.java
java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java
java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java
java/java-impl/src/com/intellij/codeInsight/lookup/PsiTypeLookupItem.java
java/java-tests/testData/codeInsight/completion/keywords/extends-8-result.java
java/java-tests/testData/codeInsight/completion/normalSorting/PreselectMostRelevantInTheMiddle.java [deleted file]
java/java-tests/testSrc/com/intellij/codeInsight/completion/JavadocCompletionTest.java
java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionOrderingTest.groovy
java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java
jps/jps-builders/src/org/jetbrains/jps/incremental/Paths.java
jps/jps-builders/src/org/jetbrains/jps/javac/JavacFileManager.java
platform/lang-api/src/com/intellij/codeInsight/TailType.java
platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionLookupArranger.java
platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java
platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupImpl.java
platform/lang-impl/src/com/intellij/codeInsight/template/impl/ListTemplatesHandler.java
platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateListPanel.java
platform/lang-impl/src/com/intellij/internal/DumpLookupElementWeights.java
platform/platform-api/src/com/intellij/execution/configurations/ParametersList.java
platform/platform-impl/src/com/intellij/notification/EventLog.java
platform/platform-resources-en/src/misc/registry.properties
platform/platform-tests/testSrc/com/intellij/notification/EventLogTest.groovy
platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java
platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/RollbackAction.java
plugins/gradle/testSources/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModelTest.groovy
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionData.java
plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GrCompletionWithLibraryTest.groovy
plugins/groovy/test/org/jetbrains/plugins/groovy/completion/GroovyCompletionTest.groovy
plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/GridInsertLocation.java
plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/GridSpanInsertProcessor.java [new file with mode: 0644]
plugins/ui-designer/src/com/intellij/uiDesigner/radComponents/RadAbstractGridLayoutManager.java
plugins/ui-designer/testSrc/com/intellij/uiDesigner/radComponents/GridInsertLocationTest.java

index 97807b9292df2a62d2deaea78ccff1d948e8b877..a6d238a8688ec47cf9079d03a9d62de6b5dc2d32 100644 (file)
@@ -30,6 +30,7 @@ import com.intellij.openapi.util.Condition;
 import com.intellij.ui.ScreenUtil;
 import com.intellij.ui.SimpleTextAttributes;
 import com.intellij.util.Consumer;
+import com.intellij.util.containers.ContainerUtil;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -37,10 +38,8 @@ import javax.swing.*;
 import java.awt.*;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
+import java.util.*;
+import java.util.List;
 
 /**
  * @author Eugene Zhuravlev
@@ -48,8 +47,16 @@ import java.util.Comparator;
  */
 public class JdkComboBox extends ComboBoxWithWidePopup {
 
+  @Nullable
+  private Condition<Sdk> myFilter;
+  
   public JdkComboBox(@NotNull final ProjectSdksModel jdkModel) {
-    super(new JdkComboBoxModel(jdkModel));
+    this(jdkModel, null);
+  }
+
+  public JdkComboBox(@NotNull final ProjectSdksModel jdkModel, @Nullable Condition<Sdk> filter) {
+    super(new JdkComboBoxModel(jdkModel, filter));
+    myFilter = filter;
     setRenderer(new ProjectJdkListRenderer(getRenderer()) {
       @Override
       public void doCustomize(JList list, Object value, int index, boolean selected, boolean hasFocus) {
@@ -221,7 +228,10 @@ public class JdkComboBox extends ComboBoxWithWidePopup {
     model.removeAllElements();
     model.addElement(firstItem);
     final ProjectSdksModel projectJdksModel = ProjectStructureConfigurable.getInstance(project).getProjectJdksModel();
-    final ArrayList<Sdk> projectJdks = new ArrayList<Sdk>(projectJdksModel.getProjectSdks().values());
+    List<Sdk> projectJdks = new ArrayList<Sdk>(projectJdksModel.getProjectSdks().values());
+    if (myFilter != null) {
+      projectJdks = ContainerUtil.filter(projectJdks, myFilter);
+    }
     Collections.sort(projectJdks, new Comparator<Sdk>() {
       public int compare(final Sdk o1, final Sdk o2) {
         return o1.getName().compareToIgnoreCase(o2.getName());
@@ -233,9 +243,12 @@ public class JdkComboBox extends ComboBoxWithWidePopup {
   }
 
   private static class JdkComboBoxModel extends DefaultComboBoxModel {
-    public JdkComboBoxModel(final ProjectSdksModel jdksModel) {
-      super();
-      final Sdk[] jdks = jdksModel.getSdks();
+    public JdkComboBoxModel(final ProjectSdksModel jdksModel, final @Nullable Condition<Sdk> filter) {
+      Sdk[] jdks = jdksModel.getSdks();
+      if (filter != null) {
+        final List<Sdk> filtered = ContainerUtil.filter(jdks, filter);
+        jdks = filtered.toArray(new Sdk[filtered.size()]); 
+      }
       Arrays.sort(jdks, new Comparator<Sdk>() {
         public int compare(final Sdk s1, final Sdk s2) {
           return s1.getName().compareToIgnoreCase(s2.getName());
index fa4ec428ed8643a6dec6f17dc71bda46640bcfa7..672536501f6aeeca428b2bd9b10020a906803ba1 100644 (file)
@@ -78,12 +78,12 @@ class ConstructorInsertHandler implements InsertHandler<LookupElementDecorator<L
       PostprocessReformattingAspect.getInstance(context.getProject()).doPostponedFormatting(context.getFile().getViewProvider());
     }
 
-    insertParentheses(context, delegate, psiClass, !inAnonymous && isAbstract);
-
     if (item.getDelegate() instanceof JavaPsiClassReferenceElement) {
-      DefaultInsertHandler.addImportForItem(context, delegate);
+      PsiTypeLookupItem.addImportForItem(context, psiClass);
     }
 
+    insertParentheses(context, delegate, psiClass, !inAnonymous && isAbstract);
+
     if (inAnonymous) {
       return;
     }
index 0c27706ddd30f0380a94041da2a1070564b5ccf6..13193a8c1ca455ad823b2daf2b3cd481ec8c02e8 100644 (file)
@@ -22,18 +22,16 @@ import com.intellij.codeInsight.TailTypes;
 import com.intellij.codeInsight.lookup.Lookup;
 import com.intellij.codeInsight.lookup.LookupElement;
 import com.intellij.codeInsight.lookup.LookupItem;
-import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.editor.Document;
 import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.project.Project;
-import com.intellij.psi.*;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiFile;
 import com.intellij.psi.codeStyle.CodeStyleSettings;
 import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
-import com.intellij.util.IncorrectOperationException;
 import org.jetbrains.annotations.NotNull;
 
 public class DefaultInsertHandler extends TemplateInsertHandler implements Cloneable {
-  private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.DefaultInsertHandler");
 
   public static final DefaultInsertHandler NO_TAIL_HANDLER = new DefaultInsertHandler(){
     @Override
@@ -54,8 +52,6 @@ public class DefaultInsertHandler extends TemplateInsertHandler implements Clone
     final Document document = editor.getDocument();
     PsiDocumentManager.getInstance(project).commitDocument(document);
 
-    final PsiFile file = context.getFile();
-
     TailType tailType = getTailType(completionChar, item);
 
     InsertHandlerState state = new InsertHandlerState(context.getSelectionEndOffset(), context.getSelectionEndOffset());
@@ -73,8 +69,6 @@ public class DefaultInsertHandler extends TemplateInsertHandler implements Clone
     state.caretOffset = processTail(tailType, state.caretOffset, state.tailOffset, editor);
     editor.getSelectionModel().removeSelection();
 
-    addImportForItem(context, item);
-
     if (tailType == TailType.DOT || context.getCompletionChar() == '.') {
       AutoPopupController.getInstance(project).autoPopupMemberLookup(editor, null);
     }
@@ -181,49 +175,6 @@ public class DefaultInsertHandler extends TemplateInsertHandler implements Clone
     JavaCompletionUtil.initOffsets(file, file.getProject(), offsetMap);
   }
 
-  public static void addImportForItem(InsertionContext context, LookupElement item) throws IncorrectOperationException {
-    PsiDocumentManager.getInstance(context.getProject()).commitAllDocuments();
-
-    int startOffset = context.getStartOffset();
-    PsiFile file = context.getFile();
-    Object o = item.getObject();
-    if (o instanceof PsiClass){
-      PsiClass aClass = (PsiClass)o;
-      if (aClass.getQualifiedName() == null) return;
-      final String lookupString = item.getLookupString();
-      int length = lookupString.length();
-      final int i = lookupString.indexOf('<');
-      if (i >= 0) length = i;
-      final int newOffset = addImportForClass(file, startOffset, startOffset + length, aClass);
-      JavaCompletionUtil.shortenReference(file, newOffset);
-    }
-    else if (o instanceof PsiType){
-      PsiType type = ((PsiType)o).getDeepComponentType();
-      if (type instanceof PsiClassType) {
-        PsiClass refClass = ((PsiClassType) type).resolve();
-        if (refClass != null){
-          int length = refClass.getName().length();
-          addImportForClass(file, startOffset, startOffset + length, refClass);
-        }
-      }
-    }
-    else if (o instanceof PsiMethod){
-      PsiMethod method = (PsiMethod)o;
-      if (method.isConstructor()){
-        PsiClass aClass = method.getContainingClass();
-        if (aClass != null){
-          int length = method.getName().length();
-          addImportForClass(file, startOffset, startOffset + length, aClass);
-        }
-      }
-    }
-  }
-
-  private static int addImportForClass(PsiFile file, int startOffset, int endOffset, PsiClass aClass) throws IncorrectOperationException {
-    return JavaCompletionUtil.insertClassReference(aClass, file, startOffset, endOffset);
-  }
-
-
   public static class InsertHandlerState{
     int tailOffset;
     int caretOffset;
index f539c346b66204b464137a37686673fdeb71f5cc..92a4c9dc5aa3616345fa913909f85f866de63738 100644 (file)
@@ -31,7 +31,7 @@ public class Java15CompletionData extends JavaCompletionData {
     //static keyword in static import
     {
       final CompletionVariant variant = new CompletionVariant(PsiImportList.class, new LeftNeighbour(new TextFilter (PsiKeyword.IMPORT)));
-      variant.addCompletion(PsiKeyword.STATIC, TailType.HUMBLE_SPACE);
+      variant.addCompletion(PsiKeyword.STATIC, TailType.HUMBLE_SPACE_BEFORE_WORD);
 
       registerVariant(variant);
     }
@@ -46,7 +46,7 @@ public class Java15CompletionData extends JavaCompletionData {
       final CompletionVariant variant = new CompletionVariant(PsiJavaFile.class, position);
       variant.includeScopeClass(PsiClass.class);
 
-      variant.addCompletion(PsiKeyword.INTERFACE, TailType.HUMBLE_SPACE);
+      variant.addCompletion(PsiKeyword.INTERFACE, TailType.HUMBLE_SPACE_BEFORE_WORD);
 
       registerVariant(variant);
     }
@@ -55,7 +55,7 @@ public class Java15CompletionData extends JavaCompletionData {
       final CompletionVariant variant = new CompletionVariant(PsiJavaFile.class, CLASS_START);
       variant.includeScopeClass(PsiClass.class);
 
-      variant.addCompletion(PsiKeyword.ENUM, TailType.HUMBLE_SPACE);
+      variant.addCompletion(PsiKeyword.ENUM, TailType.HUMBLE_SPACE_BEFORE_WORD);
       registerVariant(variant);
     }
 
@@ -68,8 +68,8 @@ public class Java15CompletionData extends JavaCompletionData {
       final CompletionVariant variant = new CompletionVariant(JavaMemberNameCompletionContributor.INSIDE_TYPE_PARAMS_PATTERN);
       variant.includeScopeClass(PsiVariable.class, true);
       variant.includeScopeClass(PsiExpressionStatement.class, true);
-      variant.addCompletion(PsiKeyword.SUPER, TailType.HUMBLE_SPACE);
-      variant.addCompletion(PsiKeyword.EXTENDS, TailType.HUMBLE_SPACE);
+      variant.addCompletion(PsiKeyword.SUPER, TailType.HUMBLE_SPACE_BEFORE_WORD);
+      variant.addCompletion(PsiKeyword.EXTENDS, TailType.HUMBLE_SPACE_BEFORE_WORD);
       registerVariant(variant);
     }
   }
index 12f1ec79ad7bfa98ac908142d0fbafa1b1aa0007..0cb4dbe86e39a286d899ad00f41fb64e33bbe4fd 100644 (file)
@@ -19,8 +19,7 @@ import com.intellij.codeInsight.AutoPopupController;
 import com.intellij.codeInsight.ExpectedTypeInfo;
 import com.intellij.codeInsight.ExpectedTypesProvider;
 import com.intellij.codeInsight.lookup.LookupElement;
-import com.intellij.diagnostic.LogMessageEx;
-import com.intellij.diagnostic.errordialog.Attachment;
+import com.intellij.codeInsight.lookup.PsiTypeLookupItem;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.editor.Document;
 import com.intellij.openapi.editor.Editor;
@@ -90,8 +89,10 @@ class JavaClassNameInsertHandler implements InsertHandler<JavaPsiClassReferenceE
     if (fillTypeArgs) {
       context.setAddCompletionChar(false);
     }
-    
-    if (shouldInsertParentheses(psiClass, position)) {
+
+    PsiTypeLookupItem.addImportForItem(context, psiClass);
+
+    if (shouldInsertParentheses(psiClass, file.findElementAt(context.getTailOffset() - 1))) {
       if (ConstructorInsertHandler.insertParentheses(context, item, psiClass, false)) {
         fillTypeArgs |= psiClass.hasTypeParameters() && PsiUtil.getLanguageLevel(file).isAtLeast(LanguageLevel.JDK_1_5);
       }
@@ -101,15 +102,6 @@ class JavaClassNameInsertHandler implements InsertHandler<JavaPsiClassReferenceE
       AutoPopupController.getInstance(project).autoPopupParameterInfo(editor, null);
     }
 
-    LOG.assertTrue(context.getTailOffset() >= 0);
-    String docText = context.getDocument().getText();
-    DefaultInsertHandler.addImportForItem(context, item);
-    if (context.getTailOffset() < 0) {
-      LOG.error(LogMessageEx.createEvent("Tail offset degraded after insertion", "start=" + context.getStartOffset(),
-                                         new Attachment(context.getFile().getViewProvider().getVirtualFile().getPath(), docText)));
-    }
-
-
     if (annotation) {
       // Check if someone inserts annotation class that require @
       PsiElement elementAt = file.findElementAt(context.getStartOffset());
index 5d9d2a0155a4b9738de5f8fca88c4a5f8950bd75..276a5a2cdc8b43fe5db3de0f0a9ae753b4a19ac9 100644 (file)
@@ -273,7 +273,7 @@ public class JavaCompletionData extends JavaAwareCompletionData{
 // completion
       final CompletionVariant variant = new CompletionVariant(position);
       variant.includeScopeClass(PsiClass.class, true);
-      variant.addCompletion(PsiKeyword.EXTENDS, TailType.HUMBLE_SPACE);
+      variant.addCompletion(PsiKeyword.EXTENDS, TailType.HUMBLE_SPACE_BEFORE_WORD);
       variant.excludeScopeClass(PsiAnonymousClass.class);
       variant.excludeScopeClass(PsiTypeParameter.class);
 
@@ -294,7 +294,7 @@ public class JavaCompletionData extends JavaAwareCompletionData{
 // completion
       final CompletionVariant variant = new CompletionVariant(position);
       variant.includeScopeClass(PsiClass.class, true);
-      variant.addCompletion(PsiKeyword.IMPLEMENTS, TailType.HUMBLE_SPACE);
+      variant.addCompletion(PsiKeyword.IMPLEMENTS, TailType.HUMBLE_SPACE_BEFORE_WORD);
       variant.excludeScopeClass(PsiAnonymousClass.class);
 
       registerVariant(variant);
@@ -306,7 +306,7 @@ public class JavaCompletionData extends JavaAwareCompletionData{
           psiElement(PsiIdentifier.class).afterLeaf(
             psiElement().withText(string().oneOf(",", "<")).withParent(PsiTypeParameterList.class))));
       //variant.includeScopeClass(PsiClass.class, true);
-      variant.addCompletion(PsiKeyword.EXTENDS, TailType.HUMBLE_SPACE);
+      variant.addCompletion(PsiKeyword.EXTENDS, TailType.HUMBLE_SPACE_BEFORE_WORD);
       registerVariant(variant);
     }
   }
@@ -414,7 +414,7 @@ public class JavaCompletionData extends JavaAwareCompletionData{
           return TailType.SEMICOLON;
         }
 
-        return TailType.HUMBLE_SPACE;
+        return TailType.HUMBLE_SPACE_BEFORE_WORD;
       }
       scope = scope.getParent();
     }
@@ -456,7 +456,7 @@ public class JavaCompletionData extends JavaAwareCompletionData{
     }
     if (statement != null && statement.getTextRange().getStartOffset() == position.getTextRange().getStartOffset()) {
       if (!psiElement().withSuperParent(2, PsiSwitchStatement.class).accepts(statement)) {
-        result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.FINAL), TailType.HUMBLE_SPACE));
+        result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.FINAL), TailType.HUMBLE_SPACE_BEFORE_WORD));
       }
     }
 
@@ -508,13 +508,13 @@ public class JavaCompletionData extends JavaAwareCompletionData{
     }
 
     if (INSIDE_PARAMETER_LIST.accepts(position) && !psiElement().afterLeaf(PsiKeyword.FINAL).accepts(position) && !AFTER_DOT.accepts(position)) {
-      result.addElement(TailTypeDecorator.withTail(createKeyword(position, PsiKeyword.FINAL), TailType.HUMBLE_SPACE));
+      result.addElement(TailTypeDecorator.withTail(createKeyword(position, PsiKeyword.FINAL), TailType.HUMBLE_SPACE_BEFORE_WORD));
     }
 
     if (CLASS_START.isAcceptable(position, position) &&
         PsiTreeUtil.getNonStrictParentOfType(position, PsiLiteralExpression.class, PsiComment.class) == null) {
       for (String s : ModifierChooser.getKeywords(position)) {
-        result.addElement(new OverrideableSpace(createKeyword(position, s), TailType.HUMBLE_SPACE));
+        result.addElement(new OverrideableSpace(createKeyword(position, s), TailType.HUMBLE_SPACE_BEFORE_WORD));
       }
     }
 
@@ -589,11 +589,11 @@ public class JavaCompletionData extends JavaAwareCompletionData{
         isStatementPosition(position)) {
       for (String primitiveType : PRIMITIVE_TYPES) {
         LookupElement keyword = createKeyword(position, primitiveType);
-        result.addElement(inCast ? keyword : new OverrideableSpace(keyword, TailType.HUMBLE_SPACE));
+        result.addElement(inCast ? keyword : new OverrideableSpace(keyword, TailType.HUMBLE_SPACE_BEFORE_WORD));
       }
     }
     if (declaration) {
-      result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.VOID), TailType.HUMBLE_SPACE));
+      result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.VOID), TailType.HUMBLE_SPACE_BEFORE_WORD));
     }
   }
 
@@ -606,7 +606,7 @@ public class JavaCompletionData extends JavaAwareCompletionData{
     if (psiElement().insideSequence(true, psiElement(PsiLabeledStatement.class),
                                     or(psiElement(PsiFile.class), psiElement(PsiMethod.class),
                                        psiElement(PsiClassInitializer.class))).accepts(position)) {
-      tailType = TailType.HUMBLE_SPACE;
+      tailType = TailType.HUMBLE_SPACE_BEFORE_WORD;
     }
     else {
       tailType = TailType.SEMICOLON;
index d876f0ad9ba88929b31a19e5f58ff7f3d91603f9..c081d03ff391f2f98d0129f4ea430d021f4973e4 100644 (file)
@@ -429,7 +429,7 @@ public class JavaCompletionUtil {
 
     PsiMethodCallExpression call = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression.class);
     boolean checkInitialized = parameters.getInvocationCount() <= 1 && call != null && PsiKeyword.SUPER.equals(call.getMethodExpression().getText());
-    
+
     final JavaCompletionProcessor processor = new JavaCompletionProcessor(element, elementFilter, checkAccess, checkInitialized, filterStaticAfterInstance, nameCondition);
     javaReference.processVariants(processor);
     final Collection<CompletionElement> plainResults = processor.getResults();
@@ -690,8 +690,8 @@ public class JavaCompletionUtil {
     return null;
   }
 
-  public static int insertClassReference(@NotNull PsiClass psiClass, @NotNull PsiFile file, int offset) {
-    return insertClassReference(psiClass, file, offset, offset);
+  public static void insertClassReference(@NotNull PsiClass psiClass, @NotNull PsiFile file, int offset) {
+    insertClassReference(psiClass, file, offset, offset);
   }
 
   public static int insertClassReference(PsiClass psiClass, PsiFile file, int startOffset, int endOffset) {
@@ -707,14 +707,14 @@ public class JavaCompletionUtil {
       final PsiElement resolved = reference.resolve();
       if (resolved instanceof PsiClass) {
         if (((PsiClass)resolved).getQualifiedName() == null || manager.areElementsEquivalent(psiClass, resolved)) {
-          return startOffset;
+          return endOffset;
         }
       }
     }
 
     String name = psiClass.getName();
     if (name == null) {
-      return startOffset;
+      return endOffset;
     }
 
     assert document != null;
@@ -724,7 +724,7 @@ public class JavaCompletionUtil {
 
     PsiDocumentManager.getInstance(project).commitAllDocuments();
 
-    int newStartOffset = startOffset;
+    int newEndOffset = endOffset;
     PsiElement element = file.findElementAt(startOffset);
     if (element instanceof PsiIdentifier) {
       PsiElement parent = element.getParent();
@@ -739,7 +739,13 @@ public class JavaCompletionUtil {
 
           newElement = CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(newElement);
           if (newElement != null) {
-            newStartOffset = newElement.getTextRange().getStartOffset();
+            newEndOffset = newElement.getTextRange().getEndOffset();
+            if (newElement instanceof PsiJavaCodeReferenceElement) {
+              PsiReferenceParameterList parameterList = ((PsiJavaCodeReferenceElement)newElement).getParameterList();
+              if (parameterList != null) {
+                newEndOffset = parameterList.getTextRange().getStartOffset();
+              }
+            }
           }
 
           if (!staticImport &&
@@ -747,7 +753,7 @@ public class JavaCompletionUtil {
               !psiClass.getManager().areElementsEquivalent(psiClass, resolveReference((PsiReference)newElement))) {
             final String qName = psiClass.getQualifiedName();
             if (qName != null) {
-              document.replaceString(newStartOffset, newElement.getTextRange().getEndOffset(), qName);
+              document.replaceString(newElement.getTextRange().getStartOffset(), newEndOffset, qName);
             }
           }
         }
@@ -758,7 +764,7 @@ public class JavaCompletionUtil {
       document.deleteString(toDelete.getStartOffset(), toDelete.getEndOffset());
     }
 
-    return newStartOffset;
+    return newEndOffset;
   }
 
   @Nullable
@@ -856,9 +862,7 @@ public class JavaCompletionUtil {
   //need to shorten references in type argument list
   public static void shortenReference(final PsiFile file, final int offset) throws IncorrectOperationException {
     final PsiDocumentManager manager = PsiDocumentManager.getInstance(file.getProject());
-    final Document document = manager.getDocument(file);
-    assert document != null;
-    manager.commitDocument(document);
+    manager.commitDocument(manager.getDocument(file));
     final PsiReference ref = file.findReferenceAt(offset);
     if (ref instanceof PsiJavaCodeReferenceElement) {
       JavaCodeStyleManager.getInstance(file.getProject()).shortenClassReferences((PsiJavaCodeReferenceElement)ref);
index ee310b9cc7e05d1b580a6e7bed63331e0e9834ce..649a4ed6e7ff973314b51e7711e14639fa5c01fa 100644 (file)
@@ -264,7 +264,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
           for (PsiClassType ref : method.getThrowsList().getReferencedTypes()) {
             final PsiClass exception = ref.resolve();
             if (exception != null && throwsSet.add(exception)) {
-              result.addElement(TailTypeDecorator.withTail(new JavaPsiClassReferenceElement(exception), TailType.HUMBLE_SPACE));
+              result.addElement(TailTypeDecorator.withTail(new JavaPsiClassReferenceElement(exception), TailType.HUMBLE_SPACE_BEFORE_WORD));
             }
           }
         }
@@ -282,7 +282,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
         if (tryBlock == null) return;
 
         for (final PsiClassType type : ExceptionUtil.getThrownExceptions(tryBlock.getStatements())) {
-          result.addElement(TailTypeDecorator.withTail(PsiTypeLookupItem.createLookupItem(type, tryBlock).setInsertHandler(new DefaultInsertHandler()), TailType.HUMBLE_SPACE));
+          result.addElement(TailTypeDecorator.withTail(PsiTypeLookupItem.createLookupItem(type, tryBlock).setInsertHandler(new DefaultInsertHandler()), TailType.HUMBLE_SPACE_BEFORE_WORD));
         }
       }
     });
index 18050b94b35c505f5eeed839ecea3b8ca96c6a88..9373ca35675136cec2ced563c6638ad6e46a6136 100644 (file)
@@ -73,14 +73,13 @@ public class PsiTypeLookupItem extends LookupItem {
   public void handleInsert(InsertionContext context) {
     PsiElement position = context.getFile().findElementAt(context.getStartOffset());
     assert position != null;
+    if (getObject() instanceof PsiClass) {
+      addImportForItem(context, (PsiClass)getObject());
+    }
     context.getDocument().insertString(context.getTailOffset(), calcGenerics(position));
-    DefaultInsertHandler.addImportForItem(context, this);
-    PostprocessReformattingAspect.getInstance(context.getProject()).doPostponedFormatting();
+    JavaCompletionUtil.shortenReference(context.getFile(), context.getStartOffset());
 
     int tail = context.getTailOffset();
-    if (tail <= 0) {
-      return;
-    }
     String braces = StringUtil.repeat("[]", getBracketsCount());
     Editor editor = context.getEditor();
     if (!braces.isEmpty()) {
@@ -227,4 +226,13 @@ public class PsiTypeLookupItem extends LookupItem {
       }
     }
   }
+
+  public static void addImportForItem(InsertionContext context, PsiClass aClass) {
+    if (aClass.getQualifiedName() == null) return;
+    PsiFile file = context.getFile();
+    int newTail = JavaCompletionUtil.insertClassReference(aClass, file, context.getStartOffset(), context.getTailOffset());
+    context.setTailOffset(newTail);
+    PostprocessReformattingAspect.getInstance(context.getProject()).doPostponedFormatting();
+    JavaCompletionUtil.shortenReference(file, context.getStartOffset());
+  }
 }
index cfcb2504f90365f23da84f4f8d3088ac9dd99f53..46fe4caea6dc8b93eda2d95298eff2a0df9e85ab 100644 (file)
@@ -1,4 +1,4 @@
 class AAA{}
 
-class BBB extends AAA implements<caret> {
+class BBB extends AAA implements <caret> {
 }
diff --git a/java/java-tests/testData/codeInsight/completion/normalSorting/PreselectMostRelevantInTheMiddle.java b/java/java-tests/testData/codeInsight/completion/normalSorting/PreselectMostRelevantInTheMiddle.java
deleted file mode 100644 (file)
index e7bd758..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-class Foo {
-  int ELEMENT_A = 1;
-  int ELEMENT_B = 1;
-  int ELEMENT_C = 1;
-  int ELEMENT_D = 1;
-  int ELEMENT_E = 1;
-  int ELEMENT_F = 1;
-  int ELEMENT_G = 1;
-  int ELEMENT_H = 1;
-  int ELEMENT_I = 1;
-
-
-    {
-        El<caret>
-    }
-
-}
\ No newline at end of file
index 7aed97b25e6ca14e0ac35a28095cf853c38b829a..b7fb373b9024d2ba5249487cf840d79edc84e299 100644 (file)
@@ -74,7 +74,7 @@ public class JavadocCompletionTest extends LightFixtureCompletionTestCase {
 
   public void testSee0() throws Exception {
     configureByFile("See0.java");
-    assertStringItems("foo", "clone", "equals", "finalize", "getClass", "hashCode", "notify", "notifyAll", "Object", "registerNatives", "toString", "wait", "wait", "wait");
+    assertStringItems("foo", "clone", "equals", "getClass", "hashCode", "notify", "notifyAll", "Object", "toString", "wait", "wait", "wait", "finalize", "registerNatives");
   }
 
   public void testSee1() throws Exception {
index de77849ddd9befac6e24fe124daba5a131fd16c0..43e49fc42e02cbfe6a6c5b1dae2efcaf2b14a24c 100644 (file)
@@ -233,16 +233,6 @@ public class NormalCompletionOrderingTest extends CompletionSortingTestCase {
     checkPreferredItems(0, "FooOCSomething", "FooObjectCollector");
   }
 
-  public void testPreselectMostRelevantInTheMiddle() {
-    myFixture.addClass("package foo; public class Elaaaaaaaaaaaaaaaaaaaa {}");
-    invokeCompletion(getTestName(false) + ".java");
-    myFixture.completeBasic();
-    LookupImpl lookup = getLookup();
-    assertPreferredItems(lookup.getList().getSelectedIndex());
-    assertEquals("Elaaaaaaaaaaaaaaaaaaaa", lookup.getItems().get(0).getLookupString());
-    assertEquals("ELEMENT_A", lookup.getCurrentItem().getLookupString());
-  }
-
   public void testPreferSamePackageOverImported() {
     myFixture.addClass("package bar; public class Bar1 {}");
     myFixture.addClass("package bar; public class Bar2 {}");
index f9b0ffd9eab69eaffca5131de1f9014aef444b44..97e7156fc63df93c149684f1e1087c4a8749f472 100644 (file)
@@ -474,7 +474,7 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase {
 
   public void testVoidExpectedType() throws Throwable {
     configureByTestName();
-    assertStringItems("notify", "notifyAll", "wait", "wait", "wait", "equals", "getClass", "hashCode", "toString");
+    assertStringItems("notify", "notifyAll", "wait", "wait", "wait", "getClass", "equals", "hashCode", "toString");
     type('e');
     assertEquals("equals", assertOneElement(getLookup().getItems()).getLookupString());
     select();
index 17cd1cea16d928b7ea2dc7f013511c0136698b15..893377d034c61259a8823f9b6f41011b67385f45 100644 (file)
@@ -38,6 +38,10 @@ public class Paths {
   }
 
   public static URI toURI(String localPath) {
+    return toURI(localPath, true);
+  }
+
+  private static URI toURI(String localPath, boolean convertSpaces) {
     try {
       String p = FileUtil.toSystemIndependentName(localPath);
       if (!p.startsWith("/")) {
@@ -46,7 +50,7 @@ public class Paths {
       if (p.startsWith("//")) {
         p = "//" + p;
       }
-      return new URI("file", null, p.replaceAll(" ", "%20"), null);
+      return new URI("file", null, convertSpaces? p.replaceAll(" ", "%20") : p, null);
     }
     catch (URISyntaxException e) {
       throw new Error(e);
@@ -54,6 +58,6 @@ public class Paths {
   }
 
   public static File convertToFile(final URI uri) {
-    return new File(toURI(uri.getPath()));
+    return new File(toURI(uri.getPath(), false));
   }
 }
index 531159e48660bb25bf1d4a28e9321315090e7e99..a7aac0fce6dc9a1f3041e808e001f292696c8f7e 100644 (file)
@@ -135,7 +135,7 @@ class JavacFileManager extends ForwardingJavaFileManager<StandardJavaFileManager
   }
 
   private File findOutputDir(File src) {
-    File file = src.getParentFile();
+    File file = FileUtil.getParentFile(src);
     while (file != null) {
       for (Map.Entry<File, Set<File>> entry : myOutputsMap.entrySet()) {
         if (entry.getValue().contains(file)) {
index 10ece49eb3f2a8d7d9da76c3709173ff913df3bf..a4b31b7eb817df88976a5aee0138df87d7515461 100644 (file)
@@ -96,14 +96,15 @@ public abstract class TailType {
    */
   public static final TailType INSERT_SPACE = new CharTailType(' ', false);
   /**
-   * insert a space unless there's one at the caret position already
+   * insert a space unless there's one at the caret position already, followed by a sowrd
    */
-  public static final TailType HUMBLE_SPACE = new CharTailType(' ', false) {
+  public static final TailType HUMBLE_SPACE_BEFORE_WORD = new CharTailType(' ', false) {
 
     @Override
     public boolean isApplicable(@NotNull InsertionContext context) {
       CharSequence text = context.getDocument().getCharsSequence();
-      if (text.length() > context.getTailOffset() && text.charAt(context.getTailOffset()) == ' ') {
+      int tail = context.getTailOffset();
+      if (text.length() > tail + 1 && text.charAt(tail) == ' ' && Character.isLetter(text.charAt(tail + 1))) {
         return false;
       }
       return super.isApplicable(context);
@@ -111,7 +112,7 @@ public abstract class TailType {
 
     @Override
     public String toString() {
-      return "HUMBLE_SPACE";
+      return "HUMBLE_SPACE_BEFORE_WORD";
     }
   };
   public static final TailType DOT = new CharTailType('.');
index cb4e49160db1f6d07eda999ff916b374f15ac6ee..e7a9e1b5aa14cb5a5133506a587303e0c50b74e8 100644 (file)
@@ -86,7 +86,7 @@ public class CompletionLookupArranger extends LookupArranger {
     CompletionLocation myLocation = new CompletionLocation(indicator.getParameters());
     final StatisticsInfo main = StatisticsManager.serialize(CompletionService.STATISTICS_KEY, item, myLocation);
     final List<LookupElement> items = lookupImpl.getItems();
-    final int count = Math.min(lookupImpl.getPreferredItemsCount(), lookupImpl.getList().getSelectedIndex());
+    final int count = Math.min(3, lookupImpl.getList().getSelectedIndex());
 
     final List<StatisticsInfo> ignored = new ArrayList<StatisticsInfo>();
     for (int i = 0; i < count; i++) {
index 85c82c2e348baff8ad8db6615ffa1401872c0836..47a5c901cb7e441218ac01a3b5af6c2cdd2c8697 100644 (file)
@@ -149,12 +149,6 @@ public class LookupCellRenderer implements ListCellRenderer {
   }
 
   private Color getItemBackground(JList list, int index, boolean isSelected) {
-    final int preferredCount = myLookup.getPreferredItemsCount();
-    final boolean isPreferred = index <= preferredCount - 1 && preferredCount < list.getModel().getSize() - 1 && LookupImpl.limitRelevance();
-
-    if (isPreferred) {
-      return isSelected ? SELECTED_BACKGROUND_COLOR : PREFERRED_BACKGROUND_COLOR;
-    }
     return isSelected ? SELECTED_BACKGROUND_COLOR : BACKGROUND_COLOR;
   }
 
index 08e6b502c4f2e74208325c71266dabe400477f26..d3701d44719c1be433638e7a55d794cf323987dc 100644 (file)
@@ -48,7 +48,6 @@ import com.intellij.openapi.util.Condition;
 import com.intellij.openapi.util.Disposer;
 import com.intellij.openapi.util.IconLoader;
 import com.intellij.openapi.util.Trinity;
-import com.intellij.openapi.util.registry.Registry;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.psi.PsiDocumentManager;
 import com.intellij.psi.PsiElement;
@@ -100,7 +99,6 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
   private final Project myProject;
   private final Editor myEditor;
 
-  private int myPreferredItemsCount;
   private String myInitialPrefix;
 
   private boolean myStableStart;
@@ -258,10 +256,6 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
     }
   }
 
-  public int getPreferredItemsCount() {
-    return myPreferredItemsCount;
-  }
-
   public void markSelectionTouched() {
     if (!ApplicationManager.getApplication().isUnitTestMode()) {
       ApplicationManager.getApplication().assertIsDispatchThread();
@@ -428,7 +422,6 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
       }
     }
 
-    myPreferredItemsCount = model.size();
     myFrozenItems.clear();
     if (myShown) {
       myFrozenItems.addAll(model);
@@ -443,8 +436,6 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
         }
       });
       model.addAll(elements);
-    } else if (limitRelevance()) {
-      model.addAll(addRemainingItemsLexicographically(model, items));
     } else  {
       for (List<LookupElement> group : snapshot.second) {
         for (LookupElement element : group) {
@@ -579,16 +570,6 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
     return p;
   }
 
-  private static List<LookupElement> addRemainingItemsLexicographically(Set<LookupElement> firstItems, Collection<LookupElement> allItems) {
-    List<LookupElement> model = new ArrayList<LookupElement>();
-    for (LookupElement item : allItems) {
-      if (!firstItems.contains(item)) {
-        model.add(item);
-      }
-    }
-    return model;
-  }
-
   private void addMostRelevantItems(final Set<LookupElement> model, final Iterable<List<LookupElement>> sortedItems) {
     if (model.size() > MAX_PREFERRED_COUNT) return;
 
@@ -605,10 +586,6 @@ public class LookupImpl extends LightweightHint implements LookupEx, Disposable
     }
   }
 
-  public static boolean limitRelevance() {
-    return ApplicationManager.getApplication().isUnitTestMode() || Registry.is("limited.relevance.sorting.in.completion");
-  }
-
   public boolean isFrozen(@NotNull LookupElement element) {
     return myFrozenItems.contains(element);
   }
index aed9467de684ede81b7a4b623d1c46ec0914ffeb..5171bfca10a18fb05f77231d989e37f813bce70f 100644 (file)
@@ -71,6 +71,7 @@ public class ListTemplatesHandler implements CodeInsightActionHandler {
       return;
     }
 
+    Collections.sort(matchingTemplates, TemplateListPanel.TEMPLATE_COMPARATOR);
     showTemplatesLookup(project, editor, prefix, matchingTemplates);
   }
 
@@ -78,6 +79,30 @@ public class ListTemplatesHandler implements CodeInsightActionHandler {
                                          @NotNull String prefix, List<TemplateImpl> matchingTemplates) {
 
     final LookupImpl lookup = (LookupImpl)LookupManager.getInstance(project).createLookup(editor, LookupElement.EMPTY_ARRAY, prefix, LookupArranger.DEFAULT);
+    lookup.setArranger(new LookupArranger() {
+      /*
+      @Override
+      public Comparator<LookupElement> getItemComparator() {
+        return new Comparator<LookupElement>() {
+          @Override
+          public int compare(LookupElement o1, LookupElement o2) {
+            return o1.getLookupString().compareToIgnoreCase(o2.getLookupString());
+          }
+        };
+      }
+      */
+
+      @Override
+      public Classifier<LookupElement> createRelevanceClassifier() {
+        return new ComparingClassifier<LookupElement>(ClassifierFactory.<LookupElement>listClassifier(), "preferPrefix") {
+          @NotNull
+          @Override
+          public Comparable getWeight(LookupElement element) {
+            return !element.getLookupString().startsWith(lookup.itemPattern(element));
+          }
+        };
+      }
+    });
     for (TemplateImpl template : matchingTemplates) {
       lookup.addItem(createTemplateElement(template), new PlainPrefixMatcher(prefix));
     }
index 412d38f4c0c2cdf3d31d5c4f087897852b9b2030..8dba15828b5de82fd38fa32fafc7d2ed83d155f4 100644 (file)
@@ -63,6 +63,11 @@ public class TemplateListPanel extends JPanel implements Disposable {
   private static final String TEMPLATE_SETTINGS = "TemplateSettings";
   private static final TemplateImpl MOCK_TEMPLATE = new TemplateImpl("mockTemplate-xxx", "mockTemplateGroup-yyy");
   public static final String ABBREVIATION = "<abbreviation>";
+  public static final Comparator<TemplateImpl> TEMPLATE_COMPARATOR = new Comparator<TemplateImpl>() {
+    public int compare(final TemplateImpl o1, final TemplateImpl o2) {
+      return o1.getKey().compareToIgnoreCase(o2.getKey());
+    }
+  };
 
   static {
     MOCK_TEMPLATE.setString("");
@@ -485,7 +490,7 @@ public class TemplateListPanel extends JPanel implements Disposable {
 
     TreePath[] paths = myTree.getSelectionPaths();
     if (paths == null) return;
-    
+
     for (TreePath path : paths) {
       DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
       Object o = node.getUserObject();
@@ -652,7 +657,7 @@ public class TemplateListPanel extends JPanel implements Disposable {
         }
       })
       .install();
-    
+
     if (myTemplateGroups.size() > 0) {
       myTree.setSelectionInterval(0, 0);
     }
@@ -770,10 +775,10 @@ public class TemplateListPanel extends JPanel implements Disposable {
 
         if (enabled) {
           Set<String> oldGroups = getAllGroups(templates);
-          
+
           removeAll();
           SchemesManager<TemplateGroup, TemplateGroup> schemesManager = TemplateSettings.getInstance().getSchemesManager();
-          
+
           for (TemplateGroup group : getTemplateGroups()) {
             final String newGroupName = group.getName();
             if (!oldGroups.contains(newGroupName) && !schemesManager.isShared(group)) {
@@ -976,11 +981,7 @@ public class TemplateListPanel extends JPanel implements Disposable {
 
   private void addTemplateNodes(TemplateGroup group, CheckedTreeNode groupNode) {
     List<TemplateImpl> templates = new ArrayList<TemplateImpl>(group.getElements());
-    Collections.sort(templates, new Comparator<TemplateImpl>() {
-      public int compare(final TemplateImpl o1, final TemplateImpl o2) {
-        return o1.getKey().compareToIgnoreCase(o2.getKey());
-      }
-    });
+    Collections.sort(templates, TEMPLATE_COMPARATOR);
     for (final TemplateImpl template : templates) {
       myTemplateOptions.put(getKey(template), template.createOptions());
       myTemplateContext.put(getKey(template), template.createContext());
index 4d3cf46f6d045aa5e16ba6add8db6a3c305dc965..5ccb4bdb7cb7a60e4fb74e0795f6710600afd047 100644 (file)
@@ -26,7 +26,9 @@ import com.intellij.openapi.actionSystem.Presentation;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.project.DumbAware;
+import com.intellij.openapi.util.text.StringUtil;
 
+import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
 
@@ -50,23 +52,19 @@ public class DumpLookupElementWeights extends AnAction implements DumbAware {
   }
 
   public static void dumpLookupElementWeights(final LookupImpl lookup) {
-    final LinkedHashMap<LookupElement,StringBuilder> strings = lookup.getRelevanceStrings();
-
-    final List<LookupElement> items = lookup.getItems();
-    final int count = lookup.getPreferredItemsCount();
+    String sb = StringUtil.join(getLookupElementWeights(lookup), "\n");
+    System.out.println(sb);
+    LOG.info(sb);
+  }
 
-    for (int i = 0; i < items.size(); i++) {
-      LookupElement item = items.get(i);
+  public static List<String> getLookupElementWeights(LookupImpl lookup) {
+    final LinkedHashMap<LookupElement,StringBuilder> strings = lookup.getRelevanceStrings();
+    List<String> sb = new ArrayList<String>();
+    for (LookupElement item : lookup.getItems()) {
       String weight = strings.get(item).toString();
       final String s = item.getLookupString() + (lookup.isFrozen(item) ? "\t_first_\t" : "\t") + weight;
-      System.out.println(s);
-      LOG.info(s);
-      if (i == count - 1) {
-        final String separator = "------------";
-        System.out.println(separator);
-        LOG.info(separator);
-      }
+      sb.add(s);
     }
+    return sb;
   }
-
 }
\ No newline at end of file
index fc5b0cb81000321a5acf44450f1ce8434a7ca9f5..45d60475c89bb3e67228f640cc8dd70b9078dd53 100644 (file)
@@ -215,6 +215,10 @@ public class ParametersList implements Cloneable {
   public void replaceOrPrepend(final @NonNls String parameter, final @NonNls String replacement) {
     replaceOrAdd(parameter, replacement, 0);
   }
+  
+  public void set(int ind, final @NonNls String value) {
+    myParameters.set(ind, value);
+  }
 
   public void add(@NonNls final String name, @NonNls final String value) {
     add(name);
index 2d1e660c2c6d189cf4587d5c2bf8bc4b7de7631b..c04f7064f54494d849119eba31e86eb543a2e294 100644 (file)
@@ -24,9 +24,12 @@ import com.intellij.notification.impl.NotificationsManagerImpl;
 import com.intellij.openapi.actionSystem.*;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.components.AbstractProjectComponent;
+import com.intellij.openapi.editor.Document;
 import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.RangeMarker;
 import com.intellij.openapi.editor.actions.ScrollToTheEndToolbarAction;
 import com.intellij.openapi.editor.actions.ToggleUseSoftWrapsToolbarAction;
+import com.intellij.openapi.editor.impl.DocumentImpl;
 import com.intellij.openapi.editor.impl.softwrap.SoftWrapAppliancePlaces;
 import com.intellij.openapi.options.ShowSettingsUtil;
 import com.intellij.openapi.project.DumbAware;
@@ -43,6 +46,8 @@ import com.intellij.openapi.wm.ToolWindowManager;
 import com.intellij.ui.awt.RelativePoint;
 import com.intellij.ui.content.Content;
 import com.intellij.ui.content.ContentFactory;
+import com.intellij.util.containers.hash.LinkedHashMap;
+import com.intellij.util.text.CharArrayUtil;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -52,8 +57,9 @@ import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.TreeSet;
+import java.util.Map;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -116,67 +122,134 @@ public class EventLog implements Notifications {
   }
 
   public static LogEntry formatForLog(@NotNull final Notification notification) {
-    String content = notification.getContent();
-    String mainText = notification.getTitle();
-    boolean showMore = false;
-    if (StringUtil.isNotEmpty(content)) {
-      if (content.startsWith("<p>")) {
-        content = content.substring("<p>".length());
-      }
-
-      if (content.startsWith("<") && !content.startsWith("<a ")) {
-        showMore = true;
-      }
-      if (StringUtil.isNotEmpty(mainText)) {
-        mainText += ": ";
+    DocumentImpl document = new DocumentImpl(true);
+    AtomicBoolean showMore = new AtomicBoolean(false);
+    Map<RangeMarker, HyperlinkInfo> links = new LinkedHashMap<RangeMarker, HyperlinkInfo>();
+    List<RangeMarker> lineSeparators = new ArrayList<RangeMarker>();
+
+    boolean hasHtml = parseHtmlContent(notification, document, showMore, links, lineSeparators);
+    removeJavaNewLines(document, lineSeparators, hasHtml);
+    insertNewLineSubstitutors(document, showMore, lineSeparators);
+
+    String status = document.getText();
+
+    ArrayList<Pair<TextRange, HyperlinkInfo>> list = new ArrayList<Pair<TextRange, HyperlinkInfo>>();
+    for (RangeMarker marker : links.keySet()) {
+      if (!marker.isValid()) {
+        showMore.set(true);
+        continue;
       }
-      mainText += content;
+      list.add(Pair.create(new TextRange(marker.getStartOffset(), marker.getEndOffset()), links.get(marker)));
     }
 
-    mainText = StringUtil.replace(mainText, "&nbsp;", " ");
-    int nlIndex = eolIndex(mainText);
-    if (nlIndex >= 0) {
-      mainText = mainText.substring(0, nlIndex);
-      showMore = true;
+    if (showMore.get()) {
+      String sb = "show balloon";
+      appendText(document, " (" + sb + ")");
+      list.add(new Pair<TextRange, HyperlinkInfo>(TextRange.from(document.getTextLength() - 1 - sb.length(), sb.length()),
+                                                  new ShowBalloon(notification)));
     }
 
-    List<Pair<TextRange, HyperlinkInfo>> links = new ArrayList<Pair<TextRange, HyperlinkInfo>>();
+    return new LogEntry(document.getText(), status, list);
+  }
+
+  private static boolean parseHtmlContent(Notification notification,
+                                          Document document,
+                                          AtomicBoolean showMore,
+                                          Map<RangeMarker, HyperlinkInfo> links, List<RangeMarker> lineSeparators) {
+    String content = notification.getContent();
+    String title = notification.getTitle();
+    if (StringUtil.isNotEmpty(title)) {
+      content = title + (StringUtil.isNotEmpty(content) ? ": " + content : "");
+    }
 
-    String message = "";
+    content = StringUtil.replace(StringUtil.convertLineSeparators(content), "&nbsp;", " ");
+    boolean hasHtml = false;
     while (true) {
-      Matcher tagMatcher = TAG_PATTERN.matcher(mainText);
+      Matcher tagMatcher = TAG_PATTERN.matcher(content);
       if (!tagMatcher.find()) {
-        message += mainText;
+        appendText(document, content);
         break;
       }
-      message += mainText.substring(0, tagMatcher.start());
-      Matcher aMatcher = A_PATTERN.matcher(tagMatcher.group());
+      
+      String tagStart = tagMatcher.group();
+      appendText(document, content.substring(0, tagMatcher.start()));
+      Matcher aMatcher = A_PATTERN.matcher(tagStart);
       if (aMatcher.matches()) {
         final String href = aMatcher.group(2);
-        int linkEnd = mainText.indexOf(A_CLOSING, tagMatcher.end());
+        int linkEnd = content.indexOf(A_CLOSING, tagMatcher.end());
         if (linkEnd > 0) {
-          String linkText = mainText.substring(tagMatcher.end(), linkEnd).replaceAll(TAG_PATTERN.pattern(), "");
-
-          links.add(new Pair<TextRange, HyperlinkInfo>(TextRange.from(message.length(), linkText.length()), new NotificationHyperlinkInfo(notification, href)));
-
-          message += linkText;
-          mainText = mainText.substring(linkEnd + A_CLOSING.length());
-          continue;
+          String linkText = content.substring(tagMatcher.end(), linkEnd).replaceAll(TAG_PATTERN.pattern(), "");
+          appendText(document, linkText);
+          links.put(document.createRangeMarker(new TextRange(document.getTextLength() - linkText.length(), document.getTextLength())),
+                    new NotificationHyperlinkInfo(notification, href));
+          content = content.substring(linkEnd + A_CLOSING.length());
+        }
+      }
+      else {
+        hasHtml = true;
+        if ("<br>".equals(tagStart) ||
+            "</br>".equals(tagStart) ||
+            "</p>".equals(tagStart) ||
+            "<p>".equals(tagStart) ||
+            "<p/>".equals(tagStart)) {
+          lineSeparators.add(document.createRangeMarker(TextRange.from(document.getTextLength(), 0)));
+        }
+        else if (!"<html>".equals(tagStart) && !"</html>".equals(tagStart) && !"<body>".equals(tagStart) && !"</body>".equals(tagStart)) {
+          showMore.set(true);
         }
+        content = content.substring(tagMatcher.end());
       }
-      mainText = mainText.substring(tagMatcher.end());
     }
+    return hasHtml;
+  }
 
-    message = StringUtil.unescapeXml(StringUtil.convertLineSeparators(message));
+  private static void insertNewLineSubstitutors(Document document, AtomicBoolean showMore, List<RangeMarker> lineSeparators) {
+    for (int j = lineSeparators.size() - 1; j >= 0; j--) {
+      RangeMarker marker = lineSeparators.get(j);
+      if (!marker.isValid()) {
+        showMore.set(true);
+        continue;
+      }
+      
+      int offset = marker.getStartOffset();
+      if (offset == 0 || offset == document.getTextLength()) {
+        continue;
+      }
+      boolean spaceBefore = offset > 0 && Character.isWhitespace(document.getCharsSequence().charAt(offset - 1));
+      if (offset < document.getTextLength()) {
+        boolean spaceAfter = Character.isWhitespace(document.getCharsSequence().charAt(offset));
+        int next = CharArrayUtil.shiftForward(document.getCharsSequence(), offset, " \t");
+        if (next < document.getTextLength() && Character.isUpperCase(document.getCharsSequence().charAt(next))) {
+          document.insertString(offset, (spaceBefore ? "" : " ") + "//" + (spaceAfter ? "" : " "));
+          continue;
+        }
+        if (spaceAfter) {
+          continue;
+        }
+      }
+      if (spaceBefore) {
+        continue;
+      }
 
-    String status = message;
+      document.insertString(offset, " ");
+    }
+  }
 
-    if (showMore) {
-      message += " more ";
-      links.add(new Pair<TextRange, HyperlinkInfo>(TextRange.from(message.length() - 5, 4), new ShowBalloon(notification)));
+  private static void removeJavaNewLines(Document document, List<RangeMarker> lineSeparators, boolean hasHtml) {
+    String text = document.getText();
+    int i = -1;
+    while (true) {
+      i = text.indexOf('\n', i + 1);
+      if (i < 0) break;
+      document.deleteString(i, i + 1);
+      if (!hasHtml) {
+        lineSeparators.add(document.createRangeMarker(TextRange.from(i, 0)));
+      }
     }
+  }
 
-    return new LogEntry(message, status, links);
+  private static void appendText(Document document, String text) {
+    document.insertString(document.getTextLength(), StringUtil.unescapeXml(text));
   }
 
   public static class LogEntry {
@@ -191,22 +264,6 @@ public class EventLog implements Notifications {
     }
   }
 
-  private static int eolIndex(String mainText) {
-    TreeSet<Integer> indices = new TreeSet<Integer>();
-    indices.add(mainText.indexOf("<br>", 1));
-    indices.add(mainText.indexOf("<br/>", 1));
-    indices.add(mainText.indexOf("<p/>", 1));
-    indices.add(mainText.indexOf("<p>", 1));
-    indices.add(mainText.indexOf("\n"));
-    indices.remove(-1);
-    return indices.isEmpty() ? -1 : indices.iterator().next();
-  }
-
-  public static boolean isEventLogVisible(Project project) {
-    final ToolWindow window = getEventLog(project);
-    return window != null && window.isVisible();
-  }
-
   @Nullable
   public static ToolWindow getEventLog(Project project) {
     return project == null ? null : ToolWindowManager.getInstance(project).getToolWindow(LOG_TOOL_WINDOW_ID);
index 7b27f306f17e8c37069eee4b11071468cb4b795f..9f6a55986f075a1a255318e18598efc12c386e00 100644 (file)
@@ -171,8 +171,6 @@ documentation.component.editor.font=false
 ide.mac.useNativeClipboard=false
 
 show.all.classes.on.first.completion=false
-limited.relevance.sorting.in.completion=false
-limited.relevance.sorting.in.completion.description=Whether only 5 most relevant items are shown at the top of the completion list, or it's sorted by relevance completely
 ide.enable.toolwindow.stack=false
 
 change.signature.awesome.mode=true
index f0ac1b26be4c0ded1f3366ef9b9b32815f4b2f9b..fee62a4801f908621be45f73216b0a0ffc10922f 100644 (file)
  */
 package com.intellij.notification;
 
-import com.intellij.testFramework.UsefulTestCase;
+
+import com.intellij.openapi.util.TextRange
+import com.intellij.testFramework.LightPlatformTestCase
+import com.intellij.testFramework.PlatformTestCase
 
 /**
  * @author peter
  */
-class EventLogTest extends UsefulTestCase {
+class EventLogTest extends LightPlatformTestCase {
+
+  EventLogTest() {
+    PlatformTestCase.initPlatformLangPrefix()
+  }
 
   public void testNbsp() {
     def entry = EventLog.formatForLog(new Notification("xxx", "Title", "Hello&nbsp;world", NotificationType.ERROR))
     assert entry.message == 'Title: Hello world'
   }
 
+  public void testParseMultilineText() {
+    def entry = EventLog.formatForLog(new Notification("xxx", "Title", "<html><body> " +
+                                                                       "<font size=\"3\">first line<br>" +
+                                                                       "second line<br>" +
+                                                                       "third<br>" +
+                                                                       "<a href=\"create\">Action</a><br>" +
+                                                                       "</body></html>", NotificationType.ERROR))
+    assert entry.message == 'Title:  first line second line third // Action (show balloon)'
+    //                       0                                       40      48          60
+    assert entry.links.collect { it.first } == [new TextRange(40, 46), new TextRange(48, 60)]
+
+  }
+
+  public void testInParagraph() {
+    def entry = EventLog.formatForLog(new Notification("xxx", "Title", "<p>message</p>", NotificationType.ERROR))
+    assert entry.message == 'Title: message'
+  }
+
+  public void testJavaSeparators() {
+    def entry = EventLog.formatForLog(new Notification("xxx", "Title", "fst\nsnd", NotificationType.ERROR))
+    assert entry.message == 'Title: fst snd'
+  }
+
+  public void testLinkInTitle() {
+    def entry = EventLog.formatForLog(new Notification("xxx", '<a href="a">link</a>', "content", NotificationType.ERROR))
+    assert entry.message == 'link: content'
+    assert entry.links.collect { it.first } == [new TextRange(0, 4)]
+  }
+
 }
index 1ffb735211343cf34fc02757768a58becc3feed6..5c5a7f2a0fae104222689ddf11e3e9caf3b9a486 100644 (file)
@@ -49,6 +49,7 @@ import com.intellij.ide.startup.StartupManagerEx;
 import com.intellij.ide.startup.impl.StartupManagerImpl;
 import com.intellij.ide.structureView.StructureViewBuilder;
 import com.intellij.ide.structureView.newStructureView.StructureViewComponent;
+import com.intellij.internal.DumpLookupElementWeights;
 import com.intellij.lang.LanguageStructureViewBuilder;
 import com.intellij.openapi.Disposable;
 import com.intellij.openapi.actionSystem.*;
@@ -1747,25 +1748,12 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
     final LookupImpl lookup = getLookup();
     assertNotNull(lookup);
 
-    final LinkedHashMap<LookupElement,StringBuilder> relevanceStrings = lookup.getRelevanceStrings();
-
     final JList list = lookup.getList();
-    final List<LookupElement> model = lookup.getItems();
-    final List<String> actual = new ArrayList<String>();
-    final int count = lookup.getPreferredItemsCount();
-    for (int i = 0; i < count; i++) {
-      actual.add(model.get(i).getLookupString());
-    }
+    List<String> strings = getLookupElementStrings();
+    assert strings != null;
+    final List<String> actual = strings.subList(0, Math.min(expected.length, strings.size()));
     if (!actual.equals(Arrays.asList(expected))) {
-      final List<String> strings = new ArrayList<String>();
-      for (int i = 0; i < model.size(); i++) {
-        final LookupElement item = model.get(i);
-        strings.add(item.getLookupString() + " " + relevanceStrings.get(item));
-        if (i == count - 1) {
-          strings.add("---");
-        }
-      }
-      assertOrderedEquals(strings, expected);
+      assertOrderedEquals(DumpLookupElementWeights.getLookupElementWeights(lookup), expected);
     }
     assertEquals(selected, list.getSelectedIndex());
   }
index 2e402f5e8cca28226b95bc3f1b2aa0fa28b92f02..5857fa4f091072d429ec45499b558a9806e63fe4 100644 (file)
@@ -44,12 +44,10 @@ import com.intellij.openapi.vcs.changes.ui.RollbackProgressModifier;
 import com.intellij.openapi.vcs.rollback.RollbackEnvironment;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.openapi.vfs.VirtualFileManager;
+import com.intellij.util.containers.CollectionFactory;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
+import java.util.*;
 
 public class RollbackAction extends AnAction implements DumbAware {
   public void update(AnActionEvent e) {
@@ -106,15 +104,25 @@ public class RollbackAction extends AnAction implements DumbAware {
       new RollbackDeletionAction().actionPerformed(e);
     }
 
-    List<VirtualFile> modifiedWithoutEditing = getModifiedWithoutEditing(e);
+    LinkedHashSet<VirtualFile> modifiedWithoutEditing = getModifiedWithoutEditing(e, project);
     if (modifiedWithoutEditing != null && !modifiedWithoutEditing.isEmpty()) {
       hasChanges = true;
       rollbackModifiedWithoutEditing(project, modifiedWithoutEditing);
     }
 
-    Change[] changes = getChanges(project, e);
-    if (changes != null && (changes.length > 0 || !hasChanges)) {
-      RollbackChangesDialog.rollbackChanges(project, Arrays.asList(changes));
+    List<Change> changes = getChanges(project, e);
+    if (changes != null) {
+      if (modifiedWithoutEditing != null) {
+        for (Iterator<Change> iterator = changes.iterator(); iterator.hasNext(); ) {
+          Change next = iterator.next();
+          if (modifiedWithoutEditing.contains(next.getVirtualFile())) {
+            iterator.remove();
+          }
+        }
+      }
+      if (!changes.isEmpty() || !hasChanges) {
+        RollbackChangesDialog.rollbackChanges(project, changes);
+      }
     }
   }
 
@@ -155,9 +163,9 @@ public class RollbackAction extends AnAction implements DumbAware {
   }
 
   @Nullable
-  private static Change[] getChanges(final Project project, final AnActionEvent e) {
+  private static List<Change> getChanges(final Project project, final AnActionEvent e) {
     final ChangesCheckHelper helper = new ChangesCheckHelper(project, e);
-    if (helper.isChangesSet()) return helper.getChanges();
+    if (helper.isChangesSet()) return CollectionFactory.arrayList(helper.getChanges());
 
     final VirtualFile[] virtualFiles = e.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY);
     if (virtualFiles != null && virtualFiles.length > 0) {
@@ -165,23 +173,31 @@ public class RollbackAction extends AnAction implements DumbAware {
       for(VirtualFile file: virtualFiles) {
         result.addAll(ChangeListManager.getInstance(project).getChangesIn(file));
       }
-      return result.toArray(new Change[result.size()]);
+      return result;
     }
     return null;
   }
 
   @Nullable
-  private static List<VirtualFile> getModifiedWithoutEditing(final AnActionEvent e) {
+  private static LinkedHashSet<VirtualFile> getModifiedWithoutEditing(final AnActionEvent e, Project project) {
     final List<VirtualFile> modifiedWithoutEditing = e.getData(VcsDataKeys.MODIFIED_WITHOUT_EDITING_DATA_KEY);
     if (modifiedWithoutEditing != null && modifiedWithoutEditing.size() > 0) {
-      return modifiedWithoutEditing;
+      return new LinkedHashSet<VirtualFile>(modifiedWithoutEditing);
     }
+
+    final VirtualFile[] virtualFiles = e.getData(PlatformDataKeys.VIRTUAL_FILE_ARRAY);
+    if (virtualFiles != null && virtualFiles.length > 0) {
+      LinkedHashSet<VirtualFile> result = new LinkedHashSet<VirtualFile>(Arrays.asList(virtualFiles));
+      result.retainAll(ChangeListManager.getInstance(project).getModifiedWithoutEditing());
+      return result;
+    }
+
     return null;
   }
 
-  private static void rollbackModifiedWithoutEditing(final Project project, final List<VirtualFile> modifiedWithoutEditing) {
+  private static void rollbackModifiedWithoutEditing(final Project project, final LinkedHashSet<VirtualFile> modifiedWithoutEditing) {
     String message = (modifiedWithoutEditing.size() == 1)
-      ? VcsBundle.message("rollback.modified.without.editing.confirm.single", modifiedWithoutEditing.get(0).getPresentableUrl())
+      ? VcsBundle.message("rollback.modified.without.editing.confirm.single", modifiedWithoutEditing.iterator().next().getPresentableUrl())
       : VcsBundle.message("rollback.modified.without.editing.confirm.multiple", modifiedWithoutEditing.size());
     int rc = Messages.showYesNoDialog(project, message, VcsBundle.message("changes.action.rollback.title"), Messages.getQuestionIcon());
     if (rc != 0) {
index 593ccb1821d17437d4ac1b233b2621022301397d..c8ec3829baed1714214e849c936e85c6b09ce716 100644 (file)
@@ -6,17 +6,19 @@ import com.intellij.openapi.application.Application
 import com.intellij.openapi.application.ApplicationManager
 import com.intellij.openapi.application.ex.ApplicationInfoEx
 import com.intellij.openapi.project.Project
+import com.intellij.testFramework.SkipInHeadlessEnvironment
 import com.intellij.util.containers.ContainerUtil
 import org.jetbrains.plugins.gradle.testutil.ChangeBuilder
 import org.jetbrains.plugins.gradle.testutil.GradleProjectBuilder
 import org.jetbrains.plugins.gradle.testutil.IntellijProjectBuilder
 import org.jetbrains.plugins.gradle.testutil.ProjectStructureChecker
+import org.junit.After
 import org.junit.Before
 import org.junit.Test
 import org.picocontainer.defaults.DefaultPicoContainer
 import org.jetbrains.plugins.gradle.diff.*
 import static org.junit.Assert.assertEquals
-import com.intellij.testFramework.SkipInHeadlessEnvironment
+import com.intellij.openapi.util.Disposer
 
 /**
  * @author Denis Zhdanov
@@ -32,6 +34,7 @@ public class GradleProjectStructureChangesModelTest {
   def changes
   def treeChecker
   def container
+  Disposable disposable = [dispose: { }] as Disposable
   
   @Before
   public void setUp() {
@@ -50,7 +53,12 @@ public class GradleProjectStructureChangesModelTest {
     
     changesModel = container.getComponentInstance(GradleProjectStructureChangesModel) as GradleProjectStructureChangesModel
     def applicationInfo = [getSmallIconUrl: {"/nodes/ideaProject.png"}] as ApplicationInfoEx
-    ApplicationManager.setApplication([getComponent: { applicationInfo } ] as Application, [dispose: { }] as Disposable)
+    ApplicationManager.setApplication([getComponent: { applicationInfo } ] as Application, disposable)
+  }
+
+  @After
+  public void tearDown() {
+    Disposer.dispose(disposable)
   }
   
   @Test
index 4575552beb155d87b61a57585e15faa3d96f8711..67504d48865e96df3c148704162cdf7f675a58a7 100644 (file)
@@ -85,7 +85,7 @@ public class GroovyCompletionData {
 
       addTypeDefinitionKeywords(result, position);
       for (String keyword : addExtendsImplements(position)) {
-        result.addElement(keyword(keyword, TailType.HUMBLE_SPACE));
+        result.addElement(keyword(keyword, TailType.HUMBLE_SPACE_BEFORE_WORD));
       }
 
       registerControlCompletion(position, result);
@@ -93,7 +93,7 @@ public class GroovyCompletionData {
       if (parent instanceof GrExpression) {
         addKeywords(result, false, PsiKeyword.TRUE, PsiKeyword.FALSE, PsiKeyword.NULL, PsiKeyword.SUPER, PsiKeyword.THIS);
         result.addElement(keyword(PsiKeyword.NEW, TailType.INSERT_SPACE));
-        result.addElement(keyword("as", TailType.HUMBLE_SPACE));
+        result.addElement(keyword("as", TailType.HUMBLE_SPACE_BEFORE_WORD));
       }
 
       if (isInfixOperatorPosition(position)) {
@@ -146,7 +146,7 @@ public class GroovyCompletionData {
       addKeywords(result, true, PsiKeyword.CLASS, PsiKeyword.INTERFACE, PsiKeyword.ENUM);
     }
     if (afterAtInType(position)) {
-      result.addElement(keyword(PsiKeyword.INTERFACE, TailType.HUMBLE_SPACE));
+      result.addElement(keyword(PsiKeyword.INTERFACE, TailType.HUMBLE_SPACE_BEFORE_WORD));
     }
   }
 
@@ -187,7 +187,7 @@ public class GroovyCompletionData {
 
   public static void addKeywords(CompletionResultSet result, boolean space, String... keywords) {
     for (String s : keywords) {
-      result.addElement(keyword(s, space ? TailType.HUMBLE_SPACE : TailType.NONE));
+      result.addElement(keyword(s, space ? TailType.HUMBLE_SPACE_BEFORE_WORD : TailType.NONE));
     }
   }
 
index 9d2b20d90aaa607c6ce9641d14a8b8a6792a9e4e..fbdb4e312da7ac91e7eea4fed3aa7f75251d6d41 100644 (file)
@@ -152,20 +152,20 @@ fromThis4
 fromThis5
 overridden
 thisProp
-class
-equals
 fromSuper
 fromSuper2
+metaPropertyValues
+properties
+superProp
+class
+equals
 getProperty
 hashCode
 invokeMethod
 metaClass
-metaPropertyValues
 notify
 notifyAll
-properties
 setProperty
-superProp
 toString
 wait
 wait
index 10d443c28edc136232885ceae88aa06f7b0eb4fe..94794bebd83b7fbcf4303e43b033fba75462f105 100644 (file)
@@ -1064,7 +1064,7 @@ class X {
   }
 
   public void testInnerClassStart() {
-    checkSingleItemCompletion 'class Foo { cl<caret> }', 'class Foo { class<caret> }'
+    checkSingleItemCompletion 'class Foo { cl<caret> }', 'class Foo { class <caret> }'
   }
 
   public void testPropertyBeforeAccessor() {
@@ -1115,7 +1115,7 @@ public class KeyVO {
   public void testSpaceTail() {
     checkCompletion 'class A <caret> ArrayList {}', ' ', 'class A extends <caret> ArrayList {}'
     checkCompletion 'class A <caret> ArrayList {}', '\n', 'class A extends<caret> ArrayList {}'
-    checkSingleItemCompletion 'class Foo impl<caret> {}', 'class Foo implements<caret> {}'
+    checkSingleItemCompletion 'class Foo impl<caret> {}', 'class Foo implements <caret> {}'
   }
 
   public void testPreferInterfacesInImplements() {
index 41f0a32cfc65f2c432eabedb001a266eadb5227c..364d5879a664a9c060c5a1fb0876f53838bf6970 100644 (file)
@@ -41,6 +41,8 @@ public class GridInsertLocation extends GridDropLocation {
 
   private GridInsertMode myMode;
 
+  private boolean mySpanInsertMode;
+
   public GridInsertLocation(@NotNull final RadContainer container,
                             final int row,
                             final int column,
@@ -82,6 +84,10 @@ public class GridInsertLocation extends GridDropLocation {
     return myMode;
   }
 
+  public void setSpanInsertMode(boolean spanInsertMode) {
+    mySpanInsertMode = spanInsertMode;
+  }
+
   private boolean isColumnInsert() {
     return myMode == GridInsertMode.ColumnAfter || myMode == GridInsertMode.ColumnBefore;
   }
@@ -198,7 +204,7 @@ public class GridInsertLocation extends GridDropLocation {
       int cellWidth = vGridLines [lastColIndex] - vGridLines [insertCol];
       int cellHeight = hGridLines [lastRowIndex] - hGridLines [insertRow];
       RadComponent component = layoutManager.getComponentAtGrid(getContainer(), insertRow, insertCol);
-      if (component != null) {
+      if (component != null && mySpanInsertMode) {
         Rectangle bounds = component.getBounds();
         bounds.translate(-vGridLines [insertCol], -hGridLines [insertRow]);
 
@@ -218,6 +224,32 @@ public class GridInsertLocation extends GridDropLocation {
         }
 
         if (rcFeedback != null) {
+          boolean spanInsertMode = false;
+          
+          if (isRowInsert()) {
+            int columns = layoutManager.getGridColumnCount(getContainer());
+            for (int i = 0; i < columns; i++) {
+              if (i != insertCol && RadAbstractGridLayoutManager.getComponentAtGrid(getContainer(), insertRow, i) != null) {
+                spanInsertMode = true;
+                break;
+              }
+            }
+          } else {
+            int rows = layoutManager.getGridRowCount(getContainer());
+            for (int i = 0; i < rows; i++) {
+              if (i != insertRow && RadAbstractGridLayoutManager.getComponentAtGrid(getContainer(), i, insertCol) != null) {
+                spanInsertMode = true;
+                break;
+              }
+            }
+          }
+
+          if (!spanInsertMode) {
+            rcFeedback = null;
+          }
+        }
+
+        if (rcFeedback != null) {
           rcFeedback.translate(vGridLines [insertCol], hGridLines [insertRow]);
         }
       }
@@ -336,13 +368,17 @@ public class GridInsertLocation extends GridDropLocation {
     int cellsToInsert = 1;
     if (components.length > 0) {
       int cellSize = container.getGridCellCount(isRowInsert());
-      Rectangle rc = getDragObjectDimensions(dragObject, cell < cellSize - 1);
-      int size = isRowInsert() ? rc.height : rc.width;
-      if (size > 0) {
-        cellsToInsert = size;
+        Rectangle rc = getDragObjectDimensions(dragObject, cell < cellSize - 1);
+        int size = isRowInsert() ? rc.height : rc.width;
+        if (size > 0) {
+          cellsToInsert = size;
       }
     }
 
+    GridSpanInsertProcessor spanInsertProcessor =
+      mySpanInsertMode && dragObject.getComponentCount() == 1 ? new GridSpanInsertProcessor(container, getRow(), getColumn(), myMode,
+                                                                                            dragObject) : null;
+
     int newCell = insertGridCells(container, cell, cellsToInsert, canGrow, isRowInsert(), !isInsertAfter(), constraintsToAdjust);
     if (isRowInsert()) {
       row = newCell;
@@ -352,7 +388,15 @@ public class GridInsertLocation extends GridDropLocation {
     }
 
     if (components.length > 0) {
+      if (spanInsertProcessor != null) {
+        spanInsertProcessor.doBefore(newCell);
+      }
+
       dropIntoGrid(container, components, row, col, dragObject);
+
+      if (spanInsertProcessor != null) {
+        spanInsertProcessor.doAfter(newCell);
+      }
     }
   }
 
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/GridSpanInsertProcessor.java b/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/GridSpanInsertProcessor.java
new file mode 100644 (file)
index 0000000..79ee09e
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2000-2012 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.uiDesigner.designSurface;
+
+import com.intellij.uiDesigner.core.GridConstraints;
+import com.intellij.uiDesigner.radComponents.RadAbstractGridLayoutManager;
+import com.intellij.uiDesigner.radComponents.RadComponent;
+import com.intellij.uiDesigner.radComponents.RadContainer;
+
+import java.awt.*;
+
+/**
+ * @author Alexander Lobas
+ */
+public class GridSpanInsertProcessor {
+  private final RadContainer myContainer;
+  private final RadAbstractGridLayoutManager myLayoutManager;
+  private final int myRow;
+  private final int myColumn;
+  private GridInsertMode myMode;
+  private RadComponent myInsertCellComponent;
+
+  public GridSpanInsertProcessor(RadContainer container,
+                                 int insertRow,
+                                 int insertColumn,
+                                 GridInsertMode mode,
+                                 ComponentDragObject dragObject) {
+    myContainer = container;
+    myLayoutManager = container.getGridLayoutManager();
+    myRow = insertRow;
+    myColumn = insertColumn;
+
+    int[] vGridLines = myLayoutManager.getVerticalGridLines(container);
+    int[] hGridLines = myLayoutManager.getHorizontalGridLines(container);
+
+    RadComponent component = RadAbstractGridLayoutManager.getComponentAtGrid(container, insertRow, insertColumn);
+
+    if (component != null) {
+      int lastColIndex = insertColumn + dragObject.getColSpan(0);
+      if (lastColIndex > vGridLines.length - 1) {
+        lastColIndex = insertColumn + 1;
+      }
+
+      int lastRowIndex = insertRow + dragObject.getRowSpan(0);
+      if (lastRowIndex > hGridLines.length - 1) {
+        lastRowIndex = insertRow + 1;
+      }
+
+      Rectangle bounds = component.getBounds();
+      bounds.translate(-vGridLines[insertColumn], -hGridLines[insertRow]);
+
+      int spaceToRight = vGridLines[lastColIndex] - vGridLines[insertColumn] - (bounds.x + bounds.width);
+      int spaceBelow = hGridLines[lastRowIndex] - hGridLines[insertRow] - (bounds.y + bounds.height);
+
+      if (mode == GridInsertMode.RowBefore && bounds.y > GridInsertLocation.INSERT_RECT_MIN_SIZE) {
+        myMode = GridInsertMode.RowBefore;
+        myInsertCellComponent = component;
+      }
+      else if (mode == GridInsertMode.RowAfter && spaceBelow > GridInsertLocation.INSERT_RECT_MIN_SIZE) {
+        myMode = GridInsertMode.RowAfter;
+      }
+      else if (mode == GridInsertMode.ColumnBefore && bounds.x > GridInsertLocation.INSERT_RECT_MIN_SIZE) {
+        myMode = GridInsertMode.ColumnBefore;
+        myInsertCellComponent = component;
+      }
+      else if (mode == GridInsertMode.ColumnAfter && spaceToRight > GridInsertLocation.INSERT_RECT_MIN_SIZE) {
+        myMode = GridInsertMode.ColumnAfter;
+      }
+    }
+  }
+
+  public void doBefore(int newCell) {
+    if (myMode == GridInsertMode.RowBefore) {
+      int oldRow = myInsertCellComponent.getConstraints().getRow();
+      int columns = myLayoutManager.getGridColumnCount(myContainer);
+      for (int i = 0; i < columns; i++) {
+        if (i != myColumn) {
+          RadComponent component = RadAbstractGridLayoutManager.getComponentAtGrid(myContainer, oldRow, i);
+          if (component != null) {
+            GridConstraints constraints = component.getConstraints();
+
+            if (constraints.getRow() == oldRow) {
+              GridConstraints oldConstraints = (GridConstraints)constraints.clone();
+              constraints.setRow(newCell);
+              constraints.setRowSpan(constraints.getRowSpan() + oldRow - newCell);
+              component.fireConstraintsChanged(oldConstraints);
+            }
+
+            i = constraints.getColumn() + constraints.getColSpan() - 1;
+          }
+        }
+      }
+    }
+    else if (myMode == GridInsertMode.ColumnBefore) {
+      int oldColumn = myInsertCellComponent.getConstraints().getColumn();
+      int rows = myLayoutManager.getGridRowCount(myContainer);
+      for (int i = 0; i < rows; i++) {
+        if (i != myRow) {
+          RadComponent component = RadAbstractGridLayoutManager.getComponentAtGrid(myContainer, i, oldColumn);
+          if (component != null) {
+            GridConstraints constraints = component.getConstraints();
+
+            if (constraints.getColumn() == oldColumn) {
+              GridConstraints oldConstraints = (GridConstraints)constraints.clone();
+              constraints.setColumn(newCell);
+              constraints.setColSpan(constraints.getColSpan() + oldColumn - newCell);
+              component.fireConstraintsChanged(oldConstraints);
+            }
+
+            i = constraints.getRow() + constraints.getRowSpan() - 1;
+          }
+        }
+      }
+    }
+  }
+
+  public void doAfter(int newCell) {
+    if (myMode == GridInsertMode.RowAfter) {
+      int columns = myLayoutManager.getGridColumnCount(myContainer);
+      for (int i = 0; i < columns; i++) {
+        if (i != myColumn) {
+          RadComponent component = RadAbstractGridLayoutManager.getComponentAtGrid(myContainer, myRow, i);
+          if (component != null) {
+            GridConstraints constraints = component.getConstraints();
+            int endRow = constraints.getRow() + constraints.getRowSpan() - 1;
+
+            if (endRow == myRow) {
+              GridConstraints oldConstraints = (GridConstraints)constraints.clone();
+              constraints.setRowSpan(constraints.getRowSpan() + newCell - myRow);
+              component.fireConstraintsChanged(oldConstraints);
+            }
+
+            i = constraints.getColumn() + constraints.getColSpan() - 1;
+          }
+        }
+      }
+    }
+    else if (myMode == GridInsertMode.ColumnAfter) {
+      int rows = myLayoutManager.getGridRowCount(myContainer);
+      for (int i = 0; i < rows; i++) {
+        if (i != myRow) {
+          RadComponent component = RadAbstractGridLayoutManager.getComponentAtGrid(myContainer, i, myColumn);
+          if (component != null) {
+            GridConstraints constraints = component.getConstraints();
+            int endColumn = constraints.getColumn() + constraints.getColSpan() - 1;
+
+            if (endColumn == myColumn) {
+              GridConstraints oldConstraints = (GridConstraints)constraints.clone();
+              constraints.setColSpan(constraints.getColSpan() + newCell - myColumn);
+              component.fireConstraintsChanged(oldConstraints);
+            }
+
+            i = constraints.getRow() + constraints.getRowSpan() - 1;
+          }
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
index ccc7b57141966b3b4fab855c0c47fcfa7539ff06..2f76d26fa057cb2249214a9cee26c5ad377596c4 100644 (file)
@@ -190,6 +190,10 @@ public abstract class RadAbstractGridLayoutManager extends RadLayoutManager {
     return 0;
   }
 
+  public boolean canSpanningAllowed() {
+    return true;
+  }
+
   public boolean canResizeCells() {
     return true;
   }
@@ -301,6 +305,8 @@ public abstract class RadAbstractGridLayoutManager extends RadLayoutManager {
       mode = GridInsertMode.ColumnAfter;
     }
 
+    boolean spanInsertMode = canSpanningAllowed() && mode == null;
+    boolean normalize = true;
     final int cellWidth = vertGridLines[col + 1] - vertGridLines[col];
     final int cellHeight = horzGridLines[row + 1] - horzGridLines[row];
     if (mode == null) {
@@ -324,11 +330,15 @@ public abstract class RadAbstractGridLayoutManager extends RadLayoutManager {
         else if (dx > right && dx < cellWidth) {
           mode = GridInsertMode.ColumnAfter;
         }
+
+        normalize = false;
       }
     }
 
     if (mode != null) {
-      return new GridInsertLocation(container, row, col, mode).normalize();
+      GridInsertLocation dropLocation = new GridInsertLocation(container, row, col, mode);
+      dropLocation.setSpanInsertMode(spanInsertMode);
+      return normalize ? dropLocation.normalize() : dropLocation;
     }
     if (getComponentAtGrid(container, row, col) instanceof RadVSpacer ||
         getComponentAtGrid(container, row, col) instanceof RadHSpacer) {
index 2649de5b479f2d701861829f398388f5ce5800fd..570404c04544eb0bc573062f70303cdf843a5d59 100644 (file)
@@ -111,6 +111,31 @@ public class GridInsertLocationTest extends TestCase {
   }
 
   public void testInsertGrowMultiple() {
+    setGridSize(4, 4);
+
+    // * . . .
+    // . . . .
+    // . . . .
+    // . . . *
+
+    insertComponent(0, 0, 1, 1);
+    insertComponent(3, 3, 1, 1);
+
+    // * . . .
+    // . . . .
+    // * . . .
+    // * . . *
+    RadComponent c1 = createComponent(0, 0, 2, 1);
+    RadComponent c2 = createComponent(0, 1, 1, 1);
+
+    GridInsertLocation location = new GridInsertLocation(myContainer, 1, 0, GridInsertMode.RowAfter);
+    DraggedComponentList dcl = DraggedComponentList.withComponents(c1, c2);
+    assertTrue(location.canDrop(dcl));
+    location.processDrop(null, new RadComponent[] {c1, c2}, null, dcl);
+    assertEquals(6, myManager.getGridRowCount(myContainer));
+  }
+
+  public void testInsertGrowMultiple1x1() {
     setGridSize(2, 2);
 
     // * .
@@ -130,10 +155,10 @@ public class GridInsertLocationTest extends TestCase {
     DraggedComponentList dcl = DraggedComponentList.withComponents(c1, c2);
     assertTrue(location.canDrop(dcl));
     location.processDrop(null, new RadComponent[] {c1, c2}, null, dcl);
-    assertEquals(4, myManager.getGridRowCount(myContainer));
+    assertEquals(3, myManager.getGridRowCount(myContainer));
   }
 
-  public void testInsertGrowSingle() {
+  public void testInsertGrowSingle1x1() {
     setGridSize(2, 2);
 
     // * .
@@ -148,7 +173,30 @@ public class GridInsertLocationTest extends TestCase {
     DraggedComponentList dcl = DraggedComponentList.withComponents(myDropComponent);
     assertTrue(location.canDrop(dcl));
     doDrop(location);
-    assertEquals(4, myManager.getGridRowCount(myContainer));
+    assertEquals(3, myManager.getGridRowCount(myContainer));
+    final RadComponent addedComponent = myContainer.getComponents()[2];
+    assertEquals(1, addedComponent.getConstraints().getRowSpan());
+    assertEquals(1, addedComponent.getConstraints().getColSpan());
+
+  }
+
+  public void testInsertGrowSingle() {
+    setGridSize(4, 4);
+
+    // * . . .
+    // . . . .
+    // . . . .
+    // . . . *
+
+    insertComponent(0, 0, 1, 1);
+    insertComponent(3, 3, 1, 1);
+
+    setComponentDimensions(myDropComponent, 0, 0, 2, 2);
+    GridInsertLocation location = new GridInsertLocation(myContainer, 1, 0, GridInsertMode.RowAfter);
+    DraggedComponentList dcl = DraggedComponentList.withComponents(myDropComponent);
+    assertTrue(location.canDrop(dcl));
+    doDrop(location);
+    assertEquals(6, myManager.getGridRowCount(myContainer));
     final RadComponent addedComponent = myContainer.getComponents()[2];
     assertEquals(2, addedComponent.getConstraints().getRowSpan());
     assertEquals(2, addedComponent.getConstraints().getColSpan());