Merge branch 'master' of git@git.labs.intellij.net:idea/community
authorEugene Kudelevsky <Eugene.Kudelevsky@jetbrains.com>
Sat, 10 Apr 2010 12:07:39 +0000 (16:07 +0400)
committerEugene Kudelevsky <Eugene.Kudelevsky@jetbrains.com>
Sat, 10 Apr 2010 12:07:39 +0000 (16:07 +0400)
48 files changed:
java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/api/CompAPIDriver.java
java/compiler/impl/src/com/intellij/compiler/impl/javaCompiler/api/CompilerAPICompiler.java
java/java-impl/src/com/intellij/codeInsight/highlighting/HighlightSuppressedWarningsHandler.java
java/java-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java
java/java-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java
java/java-impl/src/com/intellij/psi/impl/search/JavaSourceFilterScope.java
java/testFramework/src/com/intellij/testFramework/LightCodeInsightTestCase.java
platform/lang-api/src/com/intellij/codeInspection/LocalInspectionTool.java
platform/lang-api/src/com/intellij/psi/impl/ElementBase.java
platform/lang-api/src/com/intellij/util/PsiIconUtil.java
platform/lang-impl/src/com/intellij/codeInsight/highlighting/HighlightUsagesHandlerBase.java
platform/lang-impl/src/com/intellij/formatting/DependantSpacingImpl.java
platform/lang-impl/src/com/intellij/formatting/FormatProcessor.java
platform/lang-impl/src/com/intellij/formatting/FormatTextRanges.java
platform/lang-impl/src/com/intellij/formatting/IndentInfo.java
platform/lang-impl/src/com/intellij/formatting/InitialInfoBuilder.java
platform/lang-impl/src/com/intellij/formatting/SpacingImpl.java
platform/lang-impl/src/com/intellij/formatting/WhiteSpace.java
platform/lang-impl/src/com/intellij/ide/projectView/impl/nodes/AbstractPsiBasedNode.java
platform/lang-impl/src/com/intellij/psi/formatter/DocumentBasedFormattingModel.java
platform/platform-api/src/com/intellij/openapi/util/Iconable.java
platform/platform-api/src/com/intellij/util/IconUtil.java
platform/platform-impl/src/com/intellij/ide/IdeEventQueue.java
platform/platform-impl/src/com/intellij/ide/passwordSafe/impl/providers/masterKey/MasterKeyPasswordSafe.java
platform/platform-impl/src/com/intellij/ide/passwordSafe/impl/providers/masterKey/PasswordDatabase.java
platform/platform-impl/src/com/intellij/ide/passwordSafe/impl/providers/masterKey/ResetPasswordDialog.java
platform/platform-impl/src/com/intellij/ide/passwordSafe/ui/PasswordSafePromptDialog.java
platform/platform-impl/src/com/intellij/ui/mac/MacFileChooserDialog.java
platform/platform-impl/src/com/intellij/ui/mac/foundation/Foundation.java
platform/platform-impl/src/com/intellij/ui/mac/foundation/FoundationLibrary.java
platform/platform-impl/src/com/intellij/ui/mac/foundation/FoundationTypeMapper.java [deleted file]
platform/platform-impl/src/com/intellij/ui/mac/foundation/ID.java
platform/platform-impl/src/com/intellij/ui/mac/growl/Growl.java
platform/platform-impl/testSrc/com/intellij/ide/passwordSafe/impl/providers/masterKey/MasterKeyPasswordSafeTest.java [new file with mode: 0644]
platform/util/src/com/intellij/util/text/CharArrayUtil.java
plugins/ant/ant.iml
plugins/ant/src/com/intellij/lang/ant/dom/AntDomElement.java [new file with mode: 0644]
plugins/ant/src/com/intellij/lang/ant/dom/AntDomFileDescription.java [new file with mode: 0644]
plugins/ant/src/com/intellij/lang/ant/dom/AntDomProject.java [new file with mode: 0644]
plugins/ant/src/com/intellij/lang/ant/dom/AntTarget.java [new file with mode: 0644]
plugins/ant/src/com/intellij/lang/ant/dom/AntTask.java [new file with mode: 0644]
plugins/ant/src/com/intellij/lang/ant/psi/impl/AntFileImpl.java
plugins/git4idea/src/git4idea/checkin/GitPushActiveBranchesDialog.java
plugins/groovy/hotswap/pluginSrc/META-INF/plugin.xml
plugins/groovy/hotswap/pluginSrc/org/jetbrains/plugins/groovy/debugger/GroovyHotSwapper.java
plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/StandardDslIndexedRootsProvider.java
plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/search/GrSourceFilterScope.java
plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenArtifactScope.java [new file with mode: 0644]

index be4f6f1703203eba412ec380d44c1bbf330a369d..dc81ab806f565f93fdc1b9f4d1164c29405069fa 100644 (file)
@@ -32,7 +32,7 @@ import java.util.concurrent.LinkedBlockingQueue;
  * @author cdr
  */
 @SuppressWarnings({"Since15"})
-public class CompAPIDriver {
+class CompAPIDriver {
   private final BlockingQueue<CompilationEvent> myCompilationResults = new LinkedBlockingQueue<CompilationEvent>();
   private static final CompilationEvent GUARD = new CompilationEvent() {
     @Override
@@ -49,7 +49,7 @@ public class CompAPIDriver {
   private volatile boolean compiling;
   private static final PrintWriter COMPILER_ERRORS = new PrintWriter(System.err);
 
-  public CompAPIDriver() {
+  CompAPIDriver() {
   }
 
   public void compile(List<String> commandLine, List<File> paths, final String outputDir) {
index 8e87a8c8da11e79287a1364aee3214deab505383..a70bd9418afe875fc965bbce0b9af83a79c5b06f 100644 (file)
@@ -16,7 +16,6 @@
 package com.intellij.compiler.impl.javaCompiler.api;
 
 import com.intellij.compiler.OutputParser;
-import com.intellij.compiler.impl.CompilerUtil;
 import com.intellij.compiler.impl.javaCompiler.BackendCompiler;
 import com.intellij.compiler.impl.javaCompiler.DependencyProcessor;
 import com.intellij.compiler.impl.javaCompiler.ModuleChunk;
@@ -30,14 +29,8 @@ import com.intellij.openapi.compiler.CompilerMessageCategory;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.fileTypes.FileType;
 import com.intellij.openapi.fileTypes.StdFileTypes;
-import com.intellij.openapi.module.Module;
 import com.intellij.openapi.options.Configurable;
 import com.intellij.openapi.project.Project;
-import com.intellij.openapi.projectRoots.JavaSdk;
-import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.openapi.roots.ModuleRootManager;
-import com.intellij.openapi.roots.ProjectRootManager;
-import com.intellij.openapi.ui.Messages;
 import com.intellij.openapi.util.Computable;
 import com.intellij.openapi.vfs.VirtualFile;
 import org.jetbrains.annotations.NonNls;
@@ -48,7 +41,10 @@ import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
 
 
 public class CompilerAPICompiler implements BackendCompiler {
@@ -65,25 +61,6 @@ public class CompilerAPICompiler implements BackendCompiler {
   }
 
   public boolean checkCompiler(final CompileScope scope) {
-    final Module[] modules = scope.getAffectedModules();
-    final Set<Sdk> checkedJdks = new HashSet<Sdk>();
-    for (final Module module : modules) {
-      final Sdk jdk  = ModuleRootManager.getInstance(module).getSdk();
-      if (jdk == null) {
-        continue;
-      }
-      checkedJdks.add(jdk);
-    }
-    Sdk projectJdk = ProjectRootManager.getInstance(myProject).getProjectJdk();
-    if (projectJdk != null) checkedJdks.add(projectJdk);
-
-    for (Sdk sdk : checkedJdks) {
-      String versionString = sdk.getVersionString();
-      if (sdk.getSdkType() instanceof JavaSdk && !CompilerUtil.isOfVersion(versionString, "1.6") && !CompilerUtil.isOfVersion(versionString, "1.7")) {
-        Messages.showErrorDialog(myProject, "Compiler API requires JDK version 6 or later: "+ versionString, "Incompatible JDK");
-        return false;
-      }
-    }
     return true;
   }
 
index 279315873977a3a47dcb8d97483f0bd5c5206f25..731956ee956dacefd683c2cfed815286e177c6cf 100644 (file)
@@ -34,7 +34,8 @@ import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.progress.ProgressIndicator;
 import com.intellij.openapi.progress.ProgressManager;
-import com.intellij.openapi.progress.Task;
+import com.intellij.openapi.progress.impl.ProgressManagerImpl;
+import com.intellij.openapi.progress.util.ProgressIndicatorBase;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.ui.popup.JBPopupFactory;
 import com.intellij.openapi.ui.popup.PopupStep;
@@ -112,30 +113,35 @@ public class HighlightSuppressedWarningsHandler extends HighlightUsagesHandlerBa
       InspectionProjectProfileManager.getInstance(project).getInspectionProfile();
     for (PsiLiteralExpression target : targets) {
       final Object value = target.getValue();
-      if (value instanceof String) {
-        final InspectionProfileEntry toolById = ((InspectionProfileImpl)inspectionProfile).getToolById(((String)value), target);
-        if (toolById instanceof LocalInspectionToolWrapper) {
-          final LocalInspectionToolWrapper tool = new LocalInspectionToolWrapper(((LocalInspectionToolWrapper)toolById).getTool());
-          final InspectionManagerEx managerEx = ((InspectionManagerEx)InspectionManagerEx.getInstance(project));
-          final GlobalInspectionContextImpl context = managerEx.createNewGlobalContext(false);
-          tool.initialize(context);
-          ((RefManagerImpl)context.getRefManager()).inspectionReadActionStarted();
-          ProgressManager.getInstance().run(new Task.Modal(project, "Collecting information...", true) {
-            @Override
-            public void run(@NotNull ProgressIndicator indicator) {
-              pass.doInspectInBatch(managerEx, Collections.<InspectionProfileEntry>singletonList(tool), false);
-            }
+      if (!(value instanceof String)) {
+        continue;
+      }
+      final InspectionProfileEntry toolById = ((InspectionProfileImpl)inspectionProfile).getToolById((String)value, target);
+      if (!(toolById instanceof LocalInspectionToolWrapper)) {
+        continue;
+      }
+      final LocalInspectionToolWrapper tool = new LocalInspectionToolWrapper(((LocalInspectionToolWrapper)toolById).getTool());
+      final InspectionManagerEx managerEx = (InspectionManagerEx)InspectionManagerEx.getInstance(project);
+      final GlobalInspectionContextImpl context = managerEx.createNewGlobalContext(false);
+      tool.initialize(context);
+      ((RefManagerImpl)context.getRefManager()).inspectionReadActionStarted();
+      ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
+      Runnable inspect = new Runnable() {
+        public void run() {
+          pass.doInspectInBatch(managerEx, Collections.<InspectionProfileEntry>singletonList(tool), false);
+        }
+      };
+      if (indicator == null) {
+        ((ProgressManagerImpl)ProgressManager.getInstance()).executeProcessUnderProgress(inspect, new ProgressIndicatorBase());
+      }
+      else {
+        inspect.run();
+      }
 
-            @Override
-            public void onSuccess() {
-              for (HighlightInfo info : pass.getInfos()) {
-                final PsiElement element = CollectHighlightsUtil.findCommonParent(myFile, info.startOffset, info.endOffset);
-                if (element != null) {
-                  addOccurrence(element);
-                }
-              }
-            }
-          });
+      for (HighlightInfo info : pass.getInfos()) {
+        final PsiElement element = CollectHighlightsUtil.findCommonParent(myFile, info.startOffset, info.endOffset);
+        if (element != null) {
+          addOccurrence(element);
         }
       }
     }
index 3d1cb7f68d1ea5d342528ab4d5a4e3d7c86ba2e1..08e2fad3750b9efc066bd703b623edd14093383c 100644 (file)
@@ -423,7 +423,9 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx implements Disposable {
         if (list == null) list = new ArrayList<PsiClass>();
         for (PsiClass aClass : classes) {
           // class file can be located in wrong place inside file system
-          if (Comparing.strEqual(((PsiClassOwner)aClass.getContainingFile()).getPackageName(), packageName)) {
+          String qualifiedName = aClass.getQualifiedName();
+          if (qualifiedName != null) qualifiedName = StringUtil.getPackageName(qualifiedName);
+          if (Comparing.strEqual(qualifiedName, packageName)) {
             list.add(aClass);
           }
         }
index 16e029aa0e179e5acdf0f618a3c4bb6bf061b2fa..4381d526f87b371e0300d16362dae8df05d08819 100644 (file)
@@ -324,12 +324,14 @@ public class PsiClassImplUtil {
   };
 
   public static Icon getClassIcon(final int flags, final PsiClass aClass) {
-    Icon symbolIcon = ElementPresentationUtil.getClassIconOfKind(aClass, ElementPresentationUtil.getBasicClassKind(aClass));
-    RowIcon baseIcon = ElementBase.createLayeredIcon(symbolIcon, 0);
+    Icon base = aClass.getUserData(Iconable.LAST_COMPUTED_ICON);
+    if (base == null) {
+      Icon symbolIcon = ElementPresentationUtil.getClassIconOfKind(aClass, ElementPresentationUtil.getBasicClassKind(aClass));
+      RowIcon baseIcon = ElementBase.createLayeredIcon(symbolIcon, 0);
+      base = ElementPresentationUtil.addVisibilityIcon(aClass, flags, baseIcon);
+    }
 
-    return IconDeferrer.getInstance().defer(ElementPresentationUtil.addVisibilityIcon(aClass, flags, baseIcon),
-                                            new ClassIconRequest(aClass, flags),
-                                            FULL_ICON_EVALUATOR);
+    return IconDeferrer.getInstance().defer(base, new ClassIconRequest(aClass, flags), FULL_ICON_EVALUATOR);
   }
 
   public static SearchScope getClassUseScope(final PsiClass aClass) {
index d45b813db9921e6c58bac873f2abc788e67419ac..6bac12cfab8cad7dcb78e1f3ad0acb5189a85e70 100644 (file)
@@ -40,10 +40,12 @@ public class JavaSourceFilterScope extends GlobalSearchScope {
   }
 
   public boolean contains(final VirtualFile file) {
+    if (myDelegate != null && !myDelegate.contains(file)) {
+      return false;
+    }
     final FileType fileType = file.getFileType();
-    return (myDelegate == null || myDelegate.contains(file)) &&
-           (StdFileTypes.JAVA == fileType && myIndex.isInSourceContent(file) ||
-            StdFileTypes.CLASS == fileType && myIndex.isInLibraryClasses(file));
+    return  StdFileTypes.JAVA == fileType && myIndex.isInSourceContent(file) ||
+            StdFileTypes.CLASS == fileType && myIndex.isInLibraryClasses(file);
   }
 
   public int compare(final VirtualFile file1, final VirtualFile file2) {
index a19e47513be4d492e151e0c25fe64c4abb08a8c0..fc8b9c8d99f6c8b7add0542d629f2050438cfac8 100644 (file)
@@ -25,6 +25,10 @@ import com.intellij.openapi.module.StdModuleTypes;
  * A TestCase for single PsiFile being opened in Editor conversion. See configureXXX and checkResultXXX method docs.
  */
 public abstract class LightCodeInsightTestCase extends LightPlatformCodeInsightTestCase {
+  protected LightCodeInsightTestCase() {
+    IdeaTestCase.initPlatformPrefix();
+  }
+
   public static JavaPsiFacadeEx getJavaFacade() {
     return JavaPsiFacadeEx.getInstanceEx(ourProject);
   }
index d808ea159e4e723e7834b6cbf4af943478d978f6..de4c774ed9617f3c4a983cb510303908e7aea402 100644 (file)
@@ -89,6 +89,15 @@ public abstract class LocalInspectionTool extends InspectionProfileEntry {
     return null;
   }
 
+  /**
+   * Override the method to provide your own inspection visitor.
+   * Visitor created must not be recursive (e.g. it must not inherit {@link com.intellij.psi.PsiRecursiveElementVisitor})
+   * since it will be fed with every element in the file anyway.
+   * Visitor created must be thread-safe since it might be called on several elements concurrently.
+   * @param holder where visitor will register problems found.
+   * @param isOnTheFly true if inspection was run in non-batch mode
+   * @return not-null visitor for this inspection.
+   */
   @NotNull
   public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
     return new PsiElementVisitor() {
index 05ab50fed5d42e3055894ad2209868bb4f7fed05..c93b7705d6c7dff2732e485326bad34e7d5945be 100644 (file)
@@ -18,19 +18,20 @@ package com.intellij.psi.impl;
 
 import com.intellij.navigation.ItemPresentation;
 import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.IconLoader;
 import com.intellij.openapi.util.Iconable;
+import com.intellij.openapi.util.Key;
 import com.intellij.openapi.util.UserDataHolderBase;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.openapi.progress.ProcessCanceledException;
 import com.intellij.openapi.project.IndexNotReadyException;
 import com.intellij.psi.PsiElement;
 import com.intellij.psi.PsiFile;
+import com.intellij.ui.IconDeferrer;
 import com.intellij.ui.LayeredIcon;
 import com.intellij.ui.RowIcon;
-import com.intellij.util.IconUtil;
-import com.intellij.util.Icons;
-import com.intellij.util.PsiIconUtil;
-import com.intellij.util.SmartList;
+import com.intellij.util.*;
+import com.intellij.util.ui.EmptyIcon;
 import org.jetbrains.annotations.Nullable;
 
 import javax.swing.*;
@@ -47,14 +48,7 @@ public abstract class ElementBase extends UserDataHolderBase implements Iconable
     if (!(this instanceof PsiElement)) return null;
 
     try {
-      final PsiElement element = (PsiElement)this;
-
-      final Icon providersIcon = PsiIconUtil.getProvidersIcon(element, flags);
-      if (providersIcon != null) {
-        return providersIcon instanceof RowIcon ? (RowIcon)providersIcon : createLayeredIcon(providersIcon, flags);
-      }
-
-      return getElementIcon(flags);
+      return computeIcon(flags);
     }
     catch (ProcessCanceledException e) {
       throw e;
@@ -68,6 +62,24 @@ public abstract class ElementBase extends UserDataHolderBase implements Iconable
       }
     }
 
+  private Icon computeIcon(final int flags) {
+    PsiElement psiElement = (PsiElement)this;
+    Icon baseIcon = psiElement.getUserData(Iconable.LAST_COMPUTED_ICON);
+    if (baseIcon == null) {
+      baseIcon = IconLoader.getIcon("/nodes/class.png");
+    }
+
+    return IconDeferrer.getInstance().defer(baseIcon, psiElement, new Function<PsiElement, Icon>() {
+      public Icon fun(PsiElement element) {
+        final Icon providersIcon = PsiIconUtil.getProvidersIcon(element, flags);
+        if (providersIcon != null) {
+          return providersIcon instanceof RowIcon ? (RowIcon)providersIcon : createLayeredIcon(providersIcon, flags);
+        }
+        return getElementIcon(flags);
+      }
+    });
+  }
+
   protected Icon getElementIcon(final int flags) {
     final PsiElement element = (PsiElement)this;
     RowIcon baseIcon;
index 8c817a1a3f03c2150c731f4384a7021bd936bacb..30537756771b9e9ea2b094d93320b77e42d86856 100644 (file)
@@ -24,6 +24,8 @@ import com.intellij.openapi.extensions.Extensions;
 import com.intellij.openapi.project.DumbService;
 import com.intellij.openapi.project.DumbAware;
 import com.intellij.psi.PsiElement;
+import com.intellij.ui.DeferredIcon;
+import com.intellij.ui.IconDeferrer;
 import org.jetbrains.annotations.Nullable;
 
 import javax.swing.*;
index 3eae46493262b09c3bd14f0dc9a0840dd713ab36..46562622f23d1f6bb2fb84232601520040636bfc 100644 (file)
@@ -102,7 +102,7 @@ public abstract class HighlightUsagesHandlerBase<T extends PsiElement> {
 
   public abstract void computeUsages(List<T> targets);
 
-  protected void addOccurrence(final PsiElement element) {
+  protected void addOccurrence(PsiElement element) {
     TextRange range = element.getTextRange();
     range = InjectedLanguageManager.getInstance(element.getProject()).injectedToHost(element, range);
     myReadUsages.add(range);
index 31212da16b56a6b96e8b284519bd89179ff10651..a500bd007e36aa24694a1d146f0adc8f55209995 100644 (file)
@@ -18,20 +18,28 @@ package com.intellij.formatting;
 
 import com.intellij.openapi.util.TextRange;
 
+/**
+ * Extends {@link SpacingImpl} in order to add notion of dependency range.
+ * <p/>
+ * <code>'Dependency'</code> here affect {@link #getMinLineFeeds() minLineFieeds} property value. See property contract for more details.
+ */
 public class DependantSpacingImpl extends SpacingImpl {
-  private final TextRange myDependance;
+  private final TextRange myDependency;
   private static final int DEPENDENCE_CONTAINS_LF_MASK = 0x10;
   private static final int LF_WAS_USED_MASK = 0x20;
 
   public DependantSpacingImpl(final int minSpaces,
                               final int maxSpaces,
-                              TextRange dependance,
+                              TextRange dependency,
                               final boolean keepLineBreaks,
                               final int keepBlankLines) {
     super(minSpaces, maxSpaces, 0, false, false, keepLineBreaks, keepBlankLines, false, 0);
-    myDependance = dependance;
+    myDependency = dependency;
   }
 
+  /**
+   * @return    <code>1</code> if dependency has line feeds; <code>0</code> otherwise
+   */
   int getMinLineFeeds() {
     if ((myFlags & DEPENDENCE_CONTAINS_LF_MASK) != 0) {
       return 1;
@@ -42,13 +50,13 @@ public class DependantSpacingImpl extends SpacingImpl {
   }
 
   public void refresh(FormatProcessor formatter) {
-    final boolean value = wasLFUsed() || formatter.containsLineFeeds(myDependance);
+    final boolean value = wasLFUsed() || formatter.containsLineFeeds(myDependency);
     if (value) myFlags |= DEPENDENCE_CONTAINS_LF_MASK;
     else myFlags &= ~DEPENDENCE_CONTAINS_LF_MASK;
   }
 
-  public TextRange getDependancy() {
-    return myDependance;
+  public TextRange getDependency() {
+    return myDependency;
   }
 
   public final void setLFWasUsed(final boolean value) {
@@ -62,6 +70,7 @@ public class DependantSpacingImpl extends SpacingImpl {
 
   @Override
   public String toString() {
-    return "<DependantSpacing: minSpaces=" + getMinSpaces() + " maxSpaces=" + getMaxSpaces() + " minLineFeeds=" + getMinLineFeeds() + " dep=" + myDependance + ">";
+    return "<DependantSpacing: minSpaces=" + getMinSpaces() + " maxSpaces=" + getMaxSpaces() + " minLineFeeds=" + getMinLineFeeds() + " dep=" +
+           myDependency + ">";
   }
 }
index d1fcf7506e103ed3211a97462f181e21d6f7be80..312d81e3b3d1abc0568cdb231b4328d69bdeed35 100644 (file)
@@ -326,7 +326,7 @@ class FormatProcessor {
 
   private void saveDependancy(final SpacingImpl spaceProperty) {
     final DependantSpacingImpl dependantSpaceProperty = (DependantSpacingImpl)spaceProperty;
-    final TextRange dependancy = dependantSpaceProperty.getDependancy();
+    final TextRange dependancy = dependantSpaceProperty.getDependency();
     if (dependantSpaceProperty.wasLFUsed()) {
       myPreviousDependancies.put(dependancy,new Pair<AbstractBlockWrapper, Boolean>(myCurrentBlock, Boolean.TRUE));
     }
@@ -344,8 +344,8 @@ class FormatProcessor {
 
     if (whiteSpace.isReadOnly() || whiteSpace.isLineFeedsAreReadOnly()) return false;
 
-    final TextRange dependancy = ((DependantSpacingImpl)spaceProperty).getDependancy();
-    return whiteSpace.getStartOffset() < dependancy.getEndOffset();
+    final TextRange dependency = ((DependantSpacingImpl)spaceProperty).getDependency();
+    return whiteSpace.getStartOffset() < dependency.getEndOffset();
   }
 
   private boolean processWrap(Spacing spacing) {
index 6de8b0935ef7af144e992d58b5934f4a805e8c41..4d424e44fc7ef5913e236de4203e49cd70b6c26a 100644 (file)
@@ -26,9 +26,17 @@ import java.util.ArrayList;
 import java.util.List;
 
 /**
+ * Collection of {@link FormatTextRange} objects with utility methods for batch processing on aggregated objects.
+ *
+ * @see FormatTextRange
  * @author yole
  */
 public class FormatTextRanges {
+
+  /**
+   * Wraps {@link TextRange} object with {@link #myProcessHeadingWhitespace} flag and provides convenient services for checking if wrapped range intersects
+   * with the given one.
+   */
   public static class FormatTextRange {
     private TextRange myRange;
     private final boolean myProcessHeadingWhitespace;
@@ -38,6 +46,21 @@ public class FormatTextRanges {
       myProcessHeadingWhitespace = processHeadingWhitespace;
     }
 
+    /**
+     * Allows to answer if given range has intersections with the range wrapped by the current {@link FormatTextRange} object.
+     * <p/>
+     * I.e. this method returns <code>true</code> (no intersections) if any of the statements below is true:
+     * <ul>
+     *   <li>given range starts after wrapped range;</li>
+     *   <li>
+     *          given range ends before wrapped range start (given range ends before or at the wrapped range start if
+     *          <code>'processHeadingWhitespace'</code> flag is set to <code>false</code>);
+     *   </li>
+     * </ul>
+     *
+     * @param range     range to check
+     * @return               <code>true</code> if given range has no intersections with the wrapped range; <code>false</code> otherwise
+     */
     public boolean isWhitespaceReadOnly(TextRange range) {
       if (range.getStartOffset() >= myRange.getEndOffset()) return true;
       if (myProcessHeadingWhitespace) {
@@ -52,6 +75,22 @@ public class FormatTextRanges {
       return myRange.getStartOffset();
     }
 
+    /**
+     * Allows to check if given range has intersections with the range wrapped by the current {@link FormatTextRange}  object.
+     * <p/>
+     * I.e. this method returns <code>true</code> (no intersections) if and only if any of conditions below is satisfied:
+     * <ul>
+     *   <li>given range starts after end of the wrapped range;</li>
+     *   <li>
+     *          given range ends before start of the wrapped range (there is a special case when given <code>'rootIsRightBlock'</code> flag
+     *          is <code>true</code> - <code>false</code> is returned if given range ends before or at start of the wrapped range);
+     *   </li>
+     * </ul>
+     *
+     * @param range                   range to check
+     * @param rootIsRightBlock    meta-information about given range that is used during final answer calculation
+     * @return                            <code>true</code> if there are no intersections between given and wrapped ranges; <code>false</code> otherwise
+     */
     public boolean isReadOnly(TextRange range, boolean rootIsRightBlock) {
       if (myRange.getStartOffset() >= range.getEndOffset() && rootIsRightBlock) {
         return false;
@@ -102,6 +141,16 @@ public class FormatTextRanges {
     return true;
   }
 
+  /**
+   * Batches {@link FormatTextRange#isReadOnly(TextRange, boolean)} operation for all aggregated ranges.
+   * <p/>
+   * I.e. this method allows to check if given range has intersections with any of aggregated ranges.
+   *
+   * @param range                     range to check
+   * @param rootIsRightBlock      flag to use during {@link FormatTextRange#isReadOnly(TextRange, boolean)} processing
+   * @return                              <code>true</code> if given range doesn't have intersections with all aggregated ranges;
+   *                                            <code>false</code> if given range intersects at least one of aggregated ranges
+   */
   public boolean isReadOnly(TextRange range, boolean rootIsRightBlock) {
     for (FormatTextRange formatTextRange : myRanges) {
       if (!formatTextRange.isReadOnly(range, rootIsRightBlock)) {
index 7c826d022d8cf91b7a472e986f507e2d6e0bb879..c2a279258152573818c9a276b0efa550060ca4f5 100644 (file)
@@ -49,6 +49,11 @@ public class IndentInfo {
     return myLineFeeds;
   }
 
+  /**
+   * Builds string that contains line feeds, white spaces and tabulation symbols known to the current {@link IndentInfo} object.
+   *
+   * @param options              indentation formatting options
+   */
   public String generateNewWhiteSpace(CodeStyleSettings.IndentOptions options) {
     StringBuffer buffer = new StringBuffer();
     StringUtil.repeatSymbol(buffer, '\n', myLineFeeds);
index 7f99f4858127e1ff9d77d6f9474557c938adb170..af1b40b3037badb9e1274cae6cd1b49408f2c44b 100644 (file)
@@ -64,7 +64,7 @@ class InitialInfoBuilder {
                                                final CodeStyleSettings.IndentOptions options,
                                                int interestingOffset) {
     final InitialInfoBuilder builder = new InitialInfoBuilder(model, affectedRanges, options, interestingOffset);
-    final AbstractBlockWrapper wrapper = builder.buildFrom(root, 0, null, null, root.getTextRange(), null, true);
+    final AbstractBlockWrapper wrapper = builder.buildFrom(root, 0, null, null, null, true);
     wrapper.setIndent((IndentImpl)Indent.getNoneIndent());
     return builder;
   }
@@ -73,7 +73,6 @@ class InitialInfoBuilder {
                                          final int index,
                                          final CompositeBlockWrapper parent,
                                          WrapImpl currentWrapParent,
-                                         final TextRange textRange,
                                          final Block parentBlock,
                                          boolean rootBlockIsRightBlock
                                          ) {
@@ -82,6 +81,7 @@ class InitialInfoBuilder {
       wrap.registerParent(currentWrapParent);
       currentWrapParent = wrap;
     }
+    TextRange textRange = rootBlock.getTextRange();
     final int blockStartOffset = textRange.getStartOffset();
 
     if (parent != null) {
@@ -115,21 +115,20 @@ class InitialInfoBuilder {
       if (isReadOnly) {
         return processSimpleBlock(rootBlock, parent, isReadOnly, textRange, index, parentBlock);
       }
-      else {
-        final List<Block> subBlocks = rootBlock.getSubBlocks();
-        if (subBlocks.isEmpty() || myReadOnlyBlockInformationProvider != null &&
-              myReadOnlyBlockInformationProvider.isReadOnly(rootBlock)) {
-          final AbstractBlockWrapper wrapper = processSimpleBlock(rootBlock, parent, isReadOnly, textRange, index, parentBlock);
-          if (!subBlocks.isEmpty()) {
-            wrapper.setIndent((IndentImpl)subBlocks.get(0).getIndent());
-          }
-          return wrapper;
-        }
-        else {
-          return processCompositeBlock(rootBlock, parent, textRange, index, subBlocks, currentWrapParent, rootBlockIsRightBlock);
+
+      final List<Block> subBlocks = rootBlock.getSubBlocks();
+      if (subBlocks.isEmpty() || myReadOnlyBlockInformationProvider != null
+                                 && myReadOnlyBlockInformationProvider.isReadOnly(rootBlock))
+      {
+        final AbstractBlockWrapper wrapper = processSimpleBlock(rootBlock, parent, isReadOnly, textRange, index, parentBlock);
+        if (!subBlocks.isEmpty()) {
+          wrapper.setIndent((IndentImpl)subBlocks.get(0).getIndent());
         }
+        return wrapper;
       }
-    } finally {
+      return processCompositeBlock(rootBlock, parent, textRange, index, currentWrapParent, rootBlockIsRightBlock);
+    }
+    finally {
       myReadOnlyBlockInformationProvider = previousProvider;
     }
   }
@@ -138,7 +137,6 @@ class InitialInfoBuilder {
                                                      final CompositeBlockWrapper parent,
                                                      final TextRange textRange,
                                                      final int index,
-                                                     final List<Block> subBlocks,
                                                      final WrapImpl currentWrapParent,
                                                      boolean rootBlockIsRightBlock
                                                      ) {
@@ -156,6 +154,7 @@ class InitialInfoBuilder {
     }
 
     Block previous = null;
+    List<Block> subBlocks = rootBlock.getSubBlocks();
     final int subBlocksCount = subBlocks.size();
     List<AbstractBlockWrapper> list = new ArrayList<AbstractBlockWrapper>(subBlocksCount);
     final boolean blocksAreReadOnly = rootBlock instanceof ReadOnlyBlockContainer || blocksMayBeOfInterest;
@@ -166,14 +165,13 @@ class InitialInfoBuilder {
         myCurrentSpaceProperty = (SpacingImpl)rootBlock.getSpacing(previous, block);
       }
 
-      final TextRange blockRange = block.getTextRange();
       boolean childBlockIsRightBlock = false;
 
       if (i == subBlocksCount - 1 && rootBlockIsRightBlock) {
         childBlockIsRightBlock = true;
       }
 
-      final AbstractBlockWrapper wrapper = buildFrom(block, i, info, currentWrapParent, blockRange,rootBlock,childBlockIsRightBlock);
+      final AbstractBlockWrapper wrapper = buildFrom(block, i, info, currentWrapParent, rootBlock,childBlockIsRightBlock);
       list.add(wrapper);
 
       if (wrapper.getIndent() == null) {
@@ -251,17 +249,13 @@ class InitialInfoBuilder {
     }
     else {
       if (myAffectedRanges == null) return false;
-      final boolean readOnly = myAffectedRanges.isWhitespaceReadOnly(myCurrentWhiteSpace.getTextRange());
-      //System.out.println("whitespace at " + myCurrentWhiteSpace.getTextRange() + (readOnly ? " is read-only" : " is not read-only"));
-      return readOnly;
+      return myAffectedRanges.isWhitespaceReadOnly(myCurrentWhiteSpace.getTextRange());
     }
   }
 
   private boolean isReadOnly(final TextRange textRange, boolean rootIsRightBlock) {
     if (myAffectedRanges == null) return false;
-    final boolean readOnly = myAffectedRanges.isReadOnly(textRange, rootIsRightBlock);
-    //System.out.println("range at " + textRange + (readOnly ? " is read-only" : " is not read-only"));
-    return readOnly;
+    return myAffectedRanges.isReadOnly(textRange, rootIsRightBlock);
   }
 
   public Map<AbstractBlockWrapper,Block> getBlockToInfoMap() {
@@ -299,7 +293,7 @@ class InitialInfoBuilder {
       buffer.append("in ").append(((FormattingDocumentModelImpl)model).getFile().getLanguage()).append("\n");
     }
 
-    buffer.append("File text:(" + model.getTextLength()+")\n'");
+    buffer.append("File text:(").append(model.getTextLength()).append(")\n'");
     buffer.append(model.getText(new TextRange(0, model.getTextLength())).toString());
     buffer.append("'\n");
 
index f299b8f79fe7daaf55920d4c80ab12b7d33f0c17..6c7ce7c690768f55cb168af5d48a36e3541066fc 100644 (file)
@@ -18,6 +18,10 @@ package com.intellij.formatting;
 
 import org.jetbrains.annotations.NonNls;
 
+/**
+ * Extends {@link Spacing} in order to keep number of additional settings like <code>'minSpaces'</code>, <code>'minLineFeeds'</code>,
+ * <code>'prefLineFeeds'</code> etc.
+ */
 class SpacingImpl extends Spacing {
   private int myMinSpaces;
   private int myKeepBlankLines;
@@ -28,7 +32,7 @@ class SpacingImpl extends Spacing {
 
   private static final int READ_ONLY_MASK = 1;
   private static final int SAFE_MASK = 2;
-  private static final int SHOULD_KEEP_LINEBEAKS_MASK = 4;
+  private static final int SHOULD_KEEP_LINE_BREAKS_MASK = 4;
   private static final int SHOULD_KEEP_FIRST_COLUMN_MASK = 8;
 
   public SpacingImpl(final int minSpaces,
@@ -57,7 +61,7 @@ class SpacingImpl extends Spacing {
     } else {
       myKeepBlankLines = keepBlankLines;
     }
-    myFlags = (isReadOnly ? READ_ONLY_MASK:0) | (safe ? SAFE_MASK:0) | (shouldKeepLineBreaks ? SHOULD_KEEP_LINEBEAKS_MASK:0) |
+    myFlags = (isReadOnly ? READ_ONLY_MASK:0) | (safe ? SAFE_MASK:0) | (shouldKeepLineBreaks ? SHOULD_KEEP_LINE_BREAKS_MASK :0) |
       (keepFirstColumn ? SHOULD_KEEP_FIRST_COLUMN_MASK:0);
   }
 
@@ -85,11 +89,16 @@ class SpacingImpl extends Spacing {
     return (myFlags & SAFE_MASK) != 0;
   }
 
+  /**
+   * Allows to ask to refresh current state using given formatter if necessary.
+   *
+   * @param formatter     formatter to use during state refresh
+   */
   public void refresh(FormatProcessor formatter) {
   }
 
   public final boolean shouldKeepLineFeeds() {
-    return (myFlags & SHOULD_KEEP_LINEBEAKS_MASK) != 0;
+    return (myFlags & SHOULD_KEEP_LINE_BREAKS_MASK) != 0;
   }
 
   public int getKeepBlankLines() {
@@ -100,6 +109,14 @@ class SpacingImpl extends Spacing {
     return (myFlags & SHOULD_KEEP_FIRST_COLUMN_MASK) != 0;
   }
 
+  /**
+   * <b>Note:</b> current implementation uses soft type check, i.e. it checks that instance of the given object IS-A {@link SpacingImpl} and compares
+   * state defined at this class only. That means that sub-classes are assumed not to override this method in order to preserve <code>'symmetric'</code> property.
+   *
+   * @param o   {@inheritDoc}
+   * @return      {@inheritDoc}
+   */
+  @Override
   public boolean equals(Object o) {
     if (!(o instanceof SpacingImpl)) return false;
     final SpacingImpl spacing = (SpacingImpl)o;
@@ -111,6 +128,7 @@ class SpacingImpl extends Spacing {
            myKeepBlankLines == spacing.myKeepBlankLines;
   }
 
+  @Override
   public int hashCode() {
     return myMinSpaces + myMaxSpaces * 29 + myMinLineFeeds * 11 + myFlags + myKeepBlankLines + myPrefLineFeeds;
   }
index 79c8206990d35b304b5afcb26705b0d8fcf4520c..1924d520a449e10fee119ff6b335d7b9b8305380 100644 (file)
@@ -18,7 +18,6 @@ package com.intellij.formatting;
 
 import com.intellij.openapi.util.Comparing;
 import com.intellij.openapi.util.TextRange;
-import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.psi.PsiElement;
 import com.intellij.psi.PsiFile;
 import com.intellij.psi.PsiWhiteSpace;
@@ -28,7 +27,26 @@ import org.jetbrains.annotations.NonNls;
 
 import java.util.ArrayList;
 
+/**
+ * Object-level representation of continuous white space at document. Either line feed or tabulation or space is considered to be <code>'white-space'</code>.
+ * I.e. document text fragment like {@code '\t   \t\t\n\t   \t'}  may be considered as a continuous white space and may be represented as a {@link WhiteSpace} object.
+ * <p/>
+ * Provides number of properties that describe encapsulated continuous white space:
+ * <ul>
+ *   <li>{@link #getLineFeeds() lineFeeds};</li>
+ *   <li>{@link #getSpaces() spaces};</li>
+ *   <li>{@link #getIndentSpaces()};</li>
+ * </ul>
+ * <p/>
+ * Provides ability to build string representation of the managed settings taking into consideration user settings for tabulation vs white space usage, tabulation
+ * size etc.
+ * <p/>
+ * Not thread-safe.
+ */
 class WhiteSpace {
+
+  private static final char LINE_FEED = '\n';
+
   private final int myStart;
   private int myEnd;
 
@@ -50,12 +68,38 @@ class WhiteSpace {
   @NonNls private static final String CDATA_START = "<![CDATA[";
   @NonNls private static final String CDATA_END = "]]>";
 
+  /**
+   * Creates new <code>WhiteSpace</code> object with the given start offset and a flag that shows if current white space is the first white space.
+   * <p/>
+   * <b>Note:</b> {@link #getEndOffset() end offset} value is the same as the {@link #getStartOffset() start offset} for the newly constructed object.
+   * {@link #append(int, FormattingDocumentModel, CodeStyleSettings.IndentOptions)} should be called in order to apply desired end offset.
+   *
+   * @param startOffset       start offset to use
+   * @param isFirst              flag that shows if current white space is the first
+   */
   public WhiteSpace(int startOffset, boolean isFirst) {
     myStart = startOffset;
     myEnd = startOffset;
     setIsFirstWhiteSpace(isFirst);
   }
 
+  /**
+   * Applies new end offset to the current {@link WhiteSpace} object.
+   * <p/>
+   * Namely, performs the following:
+   * <ol>
+   *   <li>Checks if new end offset can be applied, return in case of negative answer;</li>
+   *   <li>
+   *          Processes all new symbols introduced by the new end offset value, calculates number of line feeds, white spaces and tabulations
+   *          between them and updates {@link #getLineFeeds() lineFeeds}, {@link #getSpaces() spaces}, {@link #getIndentSpaces() indentSpaces}
+   *          and {@link #getTotalSpaces() totalSpaces} properties accordingly;
+   *    </li>
+   * </ol>
+   *
+   * @param newEndOffset      new end offset value
+   * @param model                 formatting model that is used to access to the underlying document text
+   * @param options               indent formatting options
+   */
   public void append(int newEndOffset, FormattingDocumentModel model, CodeStyleSettings.IndentOptions options) {
     final int oldEndOffset = myEnd;
     if (newEndOffset == oldEndOffset) return;
@@ -69,6 +113,7 @@ class WhiteSpace {
 
     myEnd = newEndOffset;
     TextRange range = new TextRange(myStart, myEnd);
+    CharSequence oldText = myInitial;
     myInitial = model.getText(range);
 
     if (!coveredByBlock(model)) {
@@ -79,21 +124,11 @@ class WhiteSpace {
       );
     }
 
-    final int tabsize = options.TAB_SIZE;
-    for (int i = oldEndOffset - myStart; i < newEndOffset - myStart; i++) {
-      switch (myInitial.charAt(i)) {
-        case '\n':
-          setLineFeeds(getLineFeeds() + 1);
-          mySpaces = 0;
-          myIndentSpaces = 0;
-          break;
-        case ' ':
-          mySpaces++;
-          break;
-        case '\t':
-          myIndentSpaces += tabsize;
-          break;
-      }
+    // There is a possible case that this method is called more than once on the same object. We want to
+    if (newEndOffset > oldEndOffset) {
+      refreshStateOnEndOffsetIncrease(newEndOffset, oldEndOffset, options.TAB_SIZE);
+    } else {
+      refreshStateOnEndOffsetDecrease(oldText, newEndOffset, oldEndOffset, options.TAB_SIZE);
     }
 
     if (getLineFeeds() > 0) myFlags |= CONTAINS_LF_INITIALLY;
@@ -104,6 +139,19 @@ class WhiteSpace {
     else myFlags &=~ CONTAINS_SPACES_INITIALLY;
   }
 
+  /**
+   * Allows to check if <code>'myInitial'</code> property value stands for continuous white space text.
+   * <p/>
+   * The text is considered to be continuous <code>'white space'</code> at following cases:
+   * <ul>
+   *   <li><code>'myInitial'</code> is empty string or string that contains white spaces only;</li>
+   *   <li><code>'myInitial'</code> is a <code>CDATA</code> string which content is empty or consists from white spaces only;</li>
+   *   <li><code>'myInitial'</code> string belongs to the same {@link PsiWhiteSpace} element;</li>
+   * </ul>
+   *
+   * @param model     formatting model that is used to provide access to the <code>PSI API</code> if necessary
+   * @return               <code>true</code> if <code>'myInitial'</code> property value stands for white space; <code>false</code> otherwise
+   */
   private boolean coveredByBlock(final FormattingDocumentModel model) {
     if (myInitial == null) return true;
     String s = myInitial.toString().trim();
@@ -113,6 +161,8 @@ class WhiteSpace {
     if (psiFile == null) return false;
     PsiElement start = psiFile.findElementAt(myStart);
     PsiElement end = psiFile.findElementAt(myEnd-1);
+
+    // CDATA usage at common white space stuff smells because it makes no sense in context, for example, white space for pure java block.
     if (s.startsWith(CDATA_START)) s = s.substring(CDATA_START.length());
     if (s.endsWith(CDATA_END)) s = s.substring(0, s.length() - CDATA_END.length());
     s = s.trim();
@@ -120,45 +170,83 @@ class WhiteSpace {
     return start == end && start instanceof PsiWhiteSpace; // there maybe non-white text inside CDATA-encoded injected elements
   }
 
-  public String generateWhiteSpace(CodeStyleSettings.IndentOptions options) {
-    StringBuilder buffer = new StringBuilder();
-    StringUtil.repeatSymbol(buffer, '\n', getLineFeeds());
-
-    repeatTrailingSymbols(options, buffer, myIndentSpaces, mySpaces);
-
-    return buffer.toString();
+  private void refreshStateOnEndOffsetIncrease(int newEndOffset, int oldEndOffset, int tabSize) {
+    assert newEndOffset > oldEndOffset;
+    for (int i = oldEndOffset - myStart; i < newEndOffset - myStart; i++) {
+      switch (myInitial.charAt(i)) {
+        case LINE_FEED:
+          setLineFeeds(getLineFeeds() + 1);
+          mySpaces = 0;
+          myIndentSpaces = 0;
+          break;
+        case ' ':
+          mySpaces++;
+          break;
+        case '\t':
+          myIndentSpaces += tabSize;
+          break;
+      }
+    }
   }
 
-  private static void repeatTrailingSymbols(final CodeStyleSettings.IndentOptions options,
-                                     final StringBuilder buffer,
-                                     final int indentSpaces,
-                                     final int spaces) {
-    if (options.USE_TAB_CHARACTER) {
-      if (options.SMART_TABS) {
-        int tabCount = indentSpaces / options.TAB_SIZE;
-        int leftSpaces = indentSpaces - tabCount * options.TAB_SIZE;
-        StringUtil.repeatSymbol(buffer, '\t', tabCount);
-        StringUtil.repeatSymbol(buffer, ' ', leftSpaces + spaces);
-      }
-      else {
-        int size = spaces + indentSpaces;
-        while (size > 0) {
-          if (size >= options.TAB_SIZE) {
-            buffer.append('\t');
-            size -= options.TAB_SIZE;
-          }
-          else {
-            buffer.append(' ');
-            size--;
-          }
-        }
+  private void refreshStateOnEndOffsetDecrease(CharSequence oldText, int newEndOffset, int oldEndOffset, int tabSize) {
+    assert newEndOffset < oldEndOffset;
+    int lineFeedsNumberAtRemovedText = 0;
+    int spacesNumberAtRemovedText = 0;
+    int indentSpacesNumberAtRemovedText = 0;
+    for (int i = oldEndOffset - 1; i >= newEndOffset; i--) {
+      switch (oldText.charAt(i)) {
+        case LINE_FEED: ++lineFeedsNumberAtRemovedText; break;
+        case ' ': ++spacesNumberAtRemovedText; break;
+        case '\t': indentSpacesNumberAtRemovedText += tabSize; break;
       }
     }
-    else {
-      StringUtil.repeatSymbol(buffer, ' ', spaces + indentSpaces);
+
+    // There are no line feeds at remained text, hence, we can just subtract number of spaces and indent spaces from removed text and finish.
+    if (getLineFeeds() - lineFeedsNumberAtRemovedText <= 0) {
+      setLineFeeds(0);
+      mySpaces -= spacesNumberAtRemovedText;
+      myIndentSpaces -= indentSpacesNumberAtRemovedText;
+      return;
+    }
+
+    // There are white spaces at remained text, hence, we need to calculate number of spaces and indent spaces between last line feed and new end offset.
+    int newLineFeedsNumber = getLineFeeds() - lineFeedsNumberAtRemovedText;
+    assert newLineFeedsNumber >= 0;
+    newLineFeedsNumber = newLineFeedsNumber < 0 ? 0 : newLineFeedsNumber; // Never expect the defense to be triggered. 
+    setLineFeeds(newLineFeedsNumber);
+    mySpaces = 0;
+    myIndentSpaces = 0;
+    for (int i = newEndOffset - 1, c = oldText.charAt(i); c != LINE_FEED; c = oldText.charAt(--i)) {
+      switch (c) {
+        case ' ': ++mySpaces; break;
+        case '\t': myIndentSpaces += tabSize; break;
+      }
     }
   }
 
+  /**
+   * Builds string that contains line feeds, white spaces and tabulation symbols known to the current {@link WhiteSpace} object.
+   *
+   * @param options     indentation formatting options
+   * @return                 string that contains line feeds, white spaces and tabulation symbols known to the current {@link WhiteSpace} object
+   */
+  public String generateWhiteSpace(CodeStyleSettings.IndentOptions options) {
+    return new IndentInfo(getLineFeeds(), myIndentSpaces, mySpaces).generateNewWhiteSpace(options);
+  }
+
+  /**
+   * Tries to apply given values to {@link #getSpaces() spaces} and {@link #getIndentSpaces() indentSpaces} properties accordingly.
+   * <p/>
+   * The action is not guaranteed to be executed (i.e. the it's not guaranteed that target properties return given values after this method call
+   * - see {@link #performModification(Runnable)} for more details).
+   * <p/>
+   * Moreover, the action is guaranteed to be <b>not</b> executed  if {@link #isKeepFirstColumn() keepFirstColumn} property is unset and target
+   * document string doesn't contain spaces.
+   *
+   * @param spaces      new value for the {@link #getSpaces() spaces} property
+   * @param indent       new value for the {@link #getIndentSpaces()}  indentSpaces} property
+   */
   public void setSpaces(final int spaces, final int indent) {
     performModification(new Runnable() {
       public void run() {
@@ -182,6 +270,25 @@ class WhiteSpace {
     return myEnd;
   }
 
+  /**
+   * Execute given action in a safe manner.
+   * <p/>
+   * <code>'Safe manner'</code> here means the following:
+   * <ul>
+   *   <li>don't execute the action if {@link #isIsReadOnly() isReadOnly} property value is set to <code>true</code>;</li>
+   *   <li>ensure that number of line feeds after action execution is preserved if line feeds are {@link #isLineFeedsAreReadOnly() read only};</li>
+   *   <li>
+   *        ensure the following if {@link #isIsSafe() isSafe} property is set to <code>true</code>:
+   *        <ul>
+   *          <li>
+   *            cut all white spaces and line feeds appeared after given action execution to single white space if there were no line feeds and white spaces before;
+   *          </li>
+   *        </ul>
+   *    </li>
+   * </ul>
+   *
+   * @param action      action that should be performed in a safe manner
+   */
   private void performModification(Runnable action) {
     if (isIsReadOnly()) return;
     final boolean before = doesNotContainAnySpaces();
@@ -193,6 +300,7 @@ class WhiteSpace {
     if (isIsSafe()) {
       final boolean after = doesNotContainAnySpaces();
       if (before && !after) {
+        // Actions below seem to be useless if 'after' value is 'false'. Are kept as historical heritage.
         mySpaces = 0;
         myIndentSpaces = 0;
         setLineFeeds(0);
@@ -204,6 +312,14 @@ class WhiteSpace {
     }
   }
 
+  /**
+   * Tries to ensure that {@link #getSpaces() spaces} property value is within [{@link SpacingImpl#getMinSpaces() min}; {@link SpacingImpl#getMaxSpaces()}]
+   * bounds defined by the given spacing object.
+   * <p/>
+   * The action is <b>not</b> performed if there are line feeds configured for the current {@link WhiteSpace} object ({@link #getSpaces()} != 0).
+   *
+   * @param spaceProperty     spacing settings holder
+   */
   public void arrangeSpaces(final SpacingImpl spaceProperty) {
     performModification(new Runnable() {
       public void run() {
@@ -219,10 +335,15 @@ class WhiteSpace {
         }
       }
     });
-
-
   }
 
+  /**
+   * Tries to ensure that number of line feeds managed by the current {@link WhiteSpace} is consistent to the settings defined at the given
+   * spacing property.
+   *
+   * @param spaceProperty       space settings holder
+   * @param formatProcessor    format processor to use for space settings state refreshing
+   */
   public void arrangeLineFeeds(final SpacingImpl spaceProperty, final FormatProcessor formatProcessor) {
     performModification(new Runnable() {
       public void run() {
@@ -276,6 +397,9 @@ class WhiteSpace {
     return mySpaces + myIndentSpaces;
   }
 
+  /**
+   * Tries to ensure that current {@link WhiteSpace} object contains at least one line feed.
+   */
   public void ensureLineFeed() {
     performModification(new Runnable() {
       public void run() {
@@ -291,6 +415,11 @@ class WhiteSpace {
     return isIsReadOnly() || (isIsSafe() && doesNotContainAnySpaces());
   }
 
+  /**
+   * @param ws     char sequence to check
+   * @return          <code>true</code> if given char sequence is equal to the target document text identified by start/end offsets managed by the
+   *                         current {@link WhiteSpace} object; <code>false</code> otherwise
+   */
   public boolean equalsToString(CharSequence ws) {
     if (myInitial == null) return ws.length() == 0;
     return Comparing.equal(ws,myInitial,true);
@@ -322,6 +451,15 @@ class WhiteSpace {
     return (myFlags & CONTAINS_LF_INITIALLY) != 0;
   }
 
+  /**
+   * Tries to ensure that number of line feeds and white spaces managed by the given {@link WhiteSpace} object is the same as the one defined by the
+   * given <code>'spacing'</code> object.
+   * <p/>
+   * This method may be considered a shortcut for calling {@link #arrangeLineFeeds(SpacingImpl, FormatProcessor)} and {@link #arrangeSpaces(SpacingImpl)}.
+   *
+   * @param spacing                 spacing settings holder
+   * @param formatProcessor     format processor to use to refresh state of the given <code>'spacing'</code> object
+   */
   public void removeLineFeeds(final Spacing spacing, final FormatProcessor formatProcessor) {
     performModification(new Runnable() {
       public void run() {
@@ -338,6 +476,21 @@ class WhiteSpace {
     return myIndentSpaces;
   }
 
+  /**
+   * Allows to get information about number of 'pure' white space symbols at the last line of continuous white space document text fragment represented
+   * by the current {@link WhiteSpace} object.
+   * <p/>
+   * <b>Note:</b> pay special attention to <code>'last line'</code> qualification here. Consider the following target continuous white space document fragment:
+   * <pre>
+   *        ' ws<sub>11</sub>ws<sub>12</sub>
+   *        'ws<sub>21</sub>'
+   * </pre>
+   * <p/>
+   * Here <code>'ws<sub>nm</sub>'</code> is a m-th white space symbol at the n-th line. <code>'Spaces'</code> property of
+   * {@link WhiteSpace} object for such white-space text has a value not <b>2</b> or <b>3</b> but <b>1</b>.
+   *
+   * @return      number of white spaces at the last line of target continuous white space text document fragment
+   */
   public int getSpaces() {
     return mySpaces;
   }
@@ -396,7 +549,7 @@ class WhiteSpace {
     for (int i = 0; i < lines.length - 1 && currentOffset + lines[i].length() <= offset; i++) {
       result.append(lines[i]);
       currentOffset += lines[i].length();
-      result.append('\n');
+      result.append(LINE_FEED);
       currentOffset++;
       currentLine++;
       if (currentOffset == offset) {
@@ -408,10 +561,10 @@ class WhiteSpace {
     result.append(newIndentSpaces);
     appendNonWhitespaces(result, lines, currentLine);
     if (currentLine + 1 < lines.length) {
-      result.append('\n');
+      result.append(LINE_FEED);
       for (int i = currentLine + 1; i < lines.length - 1; i++) {
         result.append(lines[i]);
-        result.append('\n');
+        result.append(LINE_FEED);
       }
       appendNonWhitespaces(result, lines, lines.length-1);
       result.append(lines[lines.length - 1]);
@@ -421,20 +574,28 @@ class WhiteSpace {
   }
 
   private static void appendNonWhitespaces(StringBuilder result, CharSequence[] lines, int currentLine) {
+    // It looks like regexp usage is too heavy here.
     if (currentLine != lines.length && !lines[currentLine].toString().matches("\\s*")) {
       result.append(lines[currentLine]);
     }
   }
 
+  /**
+   * Shows target document text fragment identified by start/end offsets as a sequence of strings.
+   * <p/>
+   * <b>Note:</b> arrays usage here is considered to be a historical heritage.
+   *
+   * @return      target document text fragment as a sequence of strings
+   */
   private CharSequence[] getInitialLines() {
     if (myInitial == null) return new CharSequence[]{""};
     final ArrayList<CharSequence> result = new ArrayList<CharSequence>();
-    StringBuffer currentLine = new StringBuffer();
+    StringBuilder currentLine = new StringBuilder();
     for (int i = 0; i < myInitial.length(); i++) {
       final char c = myInitial.charAt(i);
-      if (c == '\n') {
+      if (c == LINE_FEED) {
         result.add(currentLine);
-        currentLine = new StringBuffer();
+        currentLine = new StringBuilder();
       }
       else {
         currentLine.append(c);
@@ -444,6 +605,26 @@ class WhiteSpace {
     return result.toArray(new CharSequence[result.size()]);
   }
 
+  /**
+   * Provides access to the information about indent white spaces at last line of continuous white space text document fragment represented by the current
+   * {@link WhiteSpace} object.
+   * <p/>
+   * <code>'Indent white space'</code> here is a white space representation of tabulation symbol. User may define that he or she wants to use particular
+   * number of white spaces instead of tabulation ({@link CodeStyleSettings.IndentOptions#TAB_SIZE}). So, {@link WhiteSpace} object uses corresponding
+   * number of 'indent white spaces' for each tabulation symbol encountered at target continuous white space text document fragment.
+   * <p/>
+   * <b>Note:</b> pay special attention to <code>'last line'</code> qualification here. Consider the following target continuous white space document fragment:
+   * <pre>
+   *        ' \t\t
+   *        '\t'
+   * </pre>
+   * <p/>
+   * Let's consider that <code>'tab size'</code> is defined as four white spaces (default setting). <code>'IndentSpaces'</code> property of
+   * {@link WhiteSpace} object for such white-space text has a value not <b>8</b> or <b>12</b> but <b>4</b>, i.e. tabulation symbols from last line
+   * only are counted.
+   *
+   * @return        number of indent spaces at the last line of target continuous white space text document fragment
+   */
   public int getIndentSpaces() {
     return myIndentSpaces;
   }
@@ -452,6 +633,11 @@ class WhiteSpace {
     return myEnd - myStart;
   }
 
+  /**
+   * Provides access to the line feed symbols number at continuous white space text document fragment represented by the current {@link WhiteSpace} object.
+   *
+   * @return      line feed symbols number
+   */
   public final int getLineFeeds() {
     return myFlags >>> LF_COUNT_SHIFT;
   }
@@ -459,7 +645,7 @@ class WhiteSpace {
   public void setLineFeeds(final int lineFeeds) {
     assert lineFeeds < MAX_LF_COUNT;
     final int flags = myFlags;
-    myFlags &= ~0xFFFFFF80;
+    myFlags &= ~0xFFFFFF80; // keep only seven lower bits, i.e. drop all line feeds registered before if any
     myFlags |= (lineFeeds << LF_COUNT_SHIFT);
 
     assert getLineFeeds() == lineFeeds;
index 1f6ddbfec8989c8f7ca67b11617460201906cf7b..9ab797c6c03f39e3d0fc9c6fd4378f40414b70e0 100644 (file)
@@ -31,6 +31,7 @@ import com.intellij.openapi.module.Module;
 import com.intellij.openapi.project.IndexNotReadyException;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.Iconable;
+import com.intellij.openapi.util.UserDataHolderBase;
 import com.intellij.openapi.vcs.FileStatus;
 import com.intellij.openapi.vcs.FileStatusManager;
 import com.intellij.openapi.vfs.VirtualFile;
@@ -152,6 +153,8 @@ public abstract class AbstractPsiBasedNode<Value> extends ProjectViewNode<Value>
     for(ProjectViewNodeDecorator decorator: Extensions.getExtensions(ProjectViewNodeDecorator.EP_NAME, myProject)) {
       decorator.decorate(this, data);
     }
+
+    value.putUserData(Iconable.LAST_COMPUTED_ICON, data.getIcon(false));
   }
 
   protected int getIconableFlags() {
index a8160f51db1475b2015da05eb303e4c934084ee5..4aa36a133d366df12dc4176c1798e01196c594ab 100644 (file)
@@ -96,11 +96,10 @@ public class DocumentBasedFormattingModel implements FormattingModel {
         int at = CharArrayUtil.indexOf(myDocument.getCharsSequence(), marker, textRange.getStartOffset(), textRange.getEndOffset() + 1);
         String ws = myDocument.getCharsSequence().subSequence(textRange.getStartOffset(), textRange.getEndOffset()).toString();
         newWs = mergeWsWithCdataMarker(whiteSpace, ws, at - textRange.getStartOffset());
-        
+
         if (removesPattern(textRange, whiteSpace, marker = "]]>")) {
-          int i = newWs.lastIndexOf('\n');
-          
-          if (i > 0) {
+          int i;
+          if (newWs != null && (i = newWs.lastIndexOf('\n')) > 0) {
             int cdataStart = newWs.indexOf("<![CDATA[");
             int i2 = newWs.lastIndexOf('\n', cdataStart);
             String cdataIndent = i2 != -1 ? newWs.substring(i2 + 1, cdataStart):"";
@@ -121,8 +120,8 @@ public class DocumentBasedFormattingModel implements FormattingModel {
   }
 
   private boolean removesPattern(final TextRange textRange, final String whiteSpace, final String pattern) {
-    return CharArrayUtil.indexOf(myDocument.getCharsSequence(), pattern, textRange.getStartOffset(), textRange.getEndOffset() + 1) != -1 &&
-        CharArrayUtil.indexOf(whiteSpace, pattern, 0) == -1;
+    return CharArrayUtil.indexOf(myDocument.getCharsSequence(), pattern, textRange.getStartOffset(), textRange.getEndOffset() + 1) >= 0 &&
+        CharArrayUtil.indexOf(whiteSpace, pattern, 0) < 0;
   }
 
   public TextRange shiftIndentInsideRange(TextRange range, int indent) {
index 34251cf03cbeb7020f6e503914dd5ee90b8b3f2d..dd4979986f1644a0f676f96d07242971cb572876 100644 (file)
@@ -24,4 +24,7 @@ public interface Iconable {
   int ICON_FLAG_CLOSED = 0x0008;
 
   Icon getIcon(int flags);
+
+  Key<Icon> LAST_COMPUTED_ICON = Key.create("lastComputedIcon");
+
 }
\ No newline at end of file
index cbd8efe22e2b23712c48c37eb7db49a10ee1f99e..d5a9441a91babc52787eeb9eb50e372d252ec759 100644 (file)
@@ -36,8 +36,6 @@ import javax.swing.*;
 
 public class IconUtil {
 
-  public static final Key<Icon> LAST_FILE_ICON = Key.create("lastVFileIcon");
-
   private IconUtil() {
   }
 
@@ -88,7 +86,7 @@ public class IconUtil {
   }
 
   public static Icon getIcon(final VirtualFile file, final int flags, final Project project) {
-    Icon lastIcon = file.getUserData(LAST_FILE_ICON);
+    Icon lastIcon = file.getUserData(Iconable.LAST_COMPUTED_ICON);
 
     return IconDeferrer.getInstance().defer(lastIcon != null ? lastIcon : file.getIcon(), new FileIconKey(file, project, flags), new Function<FileIconKey, Icon>() {
       public Icon fun(final FileIconKey key) {
@@ -114,7 +112,7 @@ public class IconUtil {
           icon = new LayeredIcon(icon, Icons.LOCKED_ICON);
         }
         
-        file.putUserData(LAST_FILE_ICON, icon);
+        file.putUserData(Iconable.LAST_COMPUTED_ICON, icon);
 
         return icon;
       }
index 1f0b844e5dc11fd1cff7e7275c5dc4a919f9bc5d..dadada1715920d8e3d8811ac4bf36a0db23414a4 100644 (file)
@@ -550,19 +550,28 @@ public class IdeEventQueue extends EventQueue {
     if (Registry.is("actionSystem.fixNullFocusedComponent")) {
       final Component focusOwner = mgr.getFocusOwner();
       if (focusOwner == null) {
-        Window showingWindow = mgr.getActiveWindow();
-        if (showingWindow != null) {
-          final IdeFocusManager fm = IdeFocusManager.findInstanceByComponent(showingWindow);
-          fm.doWhenFocusSettlesDown(new Runnable() {
-            public void run() {
-              if (mgr.getFocusOwner() == null) {
-                final Application app = ApplicationManager.getApplication();
-                if (app != null && app.isActive()) {
-                  fm.requestDefaultFocus(false);
+
+        IdeEventQueue queue = IdeEventQueue.getInstance();
+        boolean mouseEventsAhead = e instanceof MouseEvent
+                                   || queue.peekEvent(MouseEvent.MOUSE_PRESSED) != null
+                                   || queue.peekEvent(MouseEvent.MOUSE_RELEASED) != null
+                                   || queue.peekEvent(MouseEvent.MOUSE_CLICKED) != null;
+
+        if (!mouseEventsAhead) {
+          Window showingWindow = mgr.getActiveWindow();
+          if (showingWindow != null) {
+            final IdeFocusManager fm = IdeFocusManager.findInstanceByComponent(showingWindow);
+            fm.doWhenFocusSettlesDown(new Runnable() {
+              public void run() {
+                if (mgr.getFocusOwner() == null) {
+                  final Application app = ApplicationManager.getApplication();
+                  if (app != null && app.isActive()) {
+                    fm.requestDefaultFocus(false);
+                  }
                 }
               }
-            }
-          });
+            });
+          }
         }
       }
     }
index 96b4431a2a8ee046b511d3d8ac935b9a819110d9..0af3d2d441e239f2dc0ede1de0df76ccc23f6baa 100644 (file)
  */
 package com.intellij.ide.passwordSafe.impl.providers.masterKey;
 
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Ref;
-import com.intellij.openapi.util.SystemInfo;
-import com.intellij.util.ui.UIUtil;
 import com.intellij.ide.passwordSafe.MasterPasswordUnavailableException;
 import com.intellij.ide.passwordSafe.PasswordSafeException;
 import com.intellij.ide.passwordSafe.impl.providers.BasePasswordSafeProvider;
 import com.intellij.ide.passwordSafe.impl.providers.ByteArrayWrapper;
 import com.intellij.ide.passwordSafe.impl.providers.EncryptionUtil;
 import com.intellij.ide.passwordSafe.impl.providers.masterKey.windows.WindowsCryptUtils;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.util.ui.UIUtil;
 
 import javax.crypto.SecretKey;
 import java.io.UnsupportedEncodingException;
@@ -36,7 +36,7 @@ import java.util.concurrent.atomic.AtomicReference;
 /**
  * The password safe that stores information in configuration file encrypted by master password
  */
-public final class MasterKeyPasswordSafe extends BasePasswordSafeProvider {
+public class MasterKeyPasswordSafe extends BasePasswordSafeProvider {
   /**
    * The test password key
    */
@@ -63,20 +63,28 @@ public final class MasterKeyPasswordSafe extends BasePasswordSafeProvider {
     this.database = database;
   }
 
+  /**
+   * @return true if the component is running in the test mode
+   */
+  protected boolean isTestMode() {
+    return false;
+  }
+
   /**
    * Reset password for the password safe (clears password database). The method is used from plugin's UI.
    *
    * @param password the password to set
-   * @param encrypt if the password should be encrypted an stored is master database
+   * @param encrypt  if the password should be encrypted an stored is master database
    */
   void resetMasterPassword(String password, boolean encrypt) {
     this.key.set(EncryptionUtil.genPasswordKey(password));
     database.clear();
     try {
       storePassword(null, MasterKeyPasswordSafe.class, testKey(password), TEST_PASSWORD_VALUE);
-      if(encrypt) {
+      if (encrypt) {
         database.setPasswordInfo(encryptPassword(password));
-      } else {
+      }
+      else {
         database.setPasswordInfo(new byte[0]);
       }
     }
@@ -160,45 +168,51 @@ public final class MasterKeyPasswordSafe extends BasePasswordSafeProvider {
    */
   @Override
   protected SecretKey key(final Project project) throws PasswordSafeException {
-    if (ApplicationManager.getApplication().isHeadlessEnvironment()) {
+    if (!isTestMode() && ApplicationManager.getApplication().isHeadlessEnvironment()) {
       throw new MasterPasswordUnavailableException("The provider is not available in headless environment");
     }
     if (key.get() == null) {
-      final Ref<PasswordSafeException> ex = new Ref<PasswordSafeException>();
-      UIUtil.invokeAndWaitIfNeeded(new Runnable() {
-        public void run() {
-          if (key.get() == null) {
-            try {
-              if (database.isEmpty()) {
-                ResetPasswordDialog.newPassword(project, MasterKeyPasswordSafe.this);
-              }
-              else {
-                if(isPasswordEncrypted()) {
-                  try {
-                     String s = decryptPassword(database.getPasswordInfo());
-                     if(setMasterPassword(s)) {
-                       return;
-                     }
-                  } catch(PasswordSafeException e) {
-                     // ignore exception and ask password
+      if (isPasswordEncrypted()) {
+        try {
+          String s = decryptPassword(database.getPasswordInfo());
+          setMasterPassword(s);
+        }
+        catch (PasswordSafeException e) {
+          // ignore exception and ask password
+        }
+      }
+      if (key.get() == null) {
+        final Ref<PasswordSafeException> ex = new Ref<PasswordSafeException>();
+        UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+          public void run() {
+            if (key.get() == null) {
+              try {
+                if (isTestMode()) {
+                  throw new MasterPasswordUnavailableException("Master password must be specified in test mode.");
+                }
+                if (database.isEmpty()) {
+                  if (!ResetPasswordDialog.newPassword(project, MasterKeyPasswordSafe.this)) {
+                    throw new MasterPasswordUnavailableException("Master password is required to store passwords in the database.");
                   }
                 }
-                MasterPasswordDialog.askPassword(project, MasterKeyPasswordSafe.this);
+                else {
+                  MasterPasswordDialog.askPassword(project, MasterKeyPasswordSafe.this);
+                }
+              }
+              catch (PasswordSafeException e) {
+                ex.set(e);
+              }
+              catch (Exception e) {
+                //noinspection ThrowableInstanceNeverThrown
+                ex.set(new MasterPasswordUnavailableException("The problem with retrieving the password", e));
               }
-            }
-            catch (PasswordSafeException e) {
-              ex.set(e);
-            }
-            catch (Exception e) {
-              //noinspection ThrowableInstanceNeverThrown
-              ex.set(new MasterPasswordUnavailableException("The problem with retrieving the password", e));
             }
           }
+        });
+        //noinspection ThrowableResultOfMethodCallIgnored
+        if (ex.get() != null) {
+          throw ex.get();
         }
-      });
-      //noinspection ThrowableResultOfMethodCallIgnored
-      if (ex.get() != null) {
-        throw ex.get();
       }
     }
     return this.key.get();
@@ -215,6 +229,17 @@ public final class MasterKeyPasswordSafe extends BasePasswordSafeProvider {
     return super.getPassword(project, requester, key);
   }
 
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void removePassword(Project project, Class requester, String key) throws PasswordSafeException {
+    if (database.isEmpty()) {
+      return;
+    }
+    super.removePassword(project, requester, key);
+  }
+
   /**
    * {@inheritDoc}
    */
index 0969292b2332c0a7de13ac74446814b272bf5323..039f1166a6f7fa290d1bdcf74177d8ea5ba19297 100644 (file)
@@ -99,7 +99,6 @@ public class PasswordDatabase implements PersistentStateComponent<PasswordDataba
    */
   public void putAll(Map<ByteArrayWrapper, byte[]> copy) {
     synchronized (myDatabase) {
-      myDatabase.clear();
       myDatabase.putAll(copy);
     }
   }
index 7135757d9e7cb84dfd0e8f267e4a200a7a9a51af..5e6a2acf55690483395576a41734f8a0c99ec738 100644 (file)
@@ -58,7 +58,7 @@ public class ResetPasswordDialog extends DialogWrapper {
     setTitle(firstTime ? "Master Password" : "Reset Master Password");
     setOKButtonText(firstTime ? "Set Password" : "Reset Password");
     if (safe.isOsProtectedPasswordSupported()) {
-      myEncryptMasterPasswordWithCheckBox.setSelected(true);
+      myEncryptMasterPasswordWithCheckBox.setSelected(false);
     }
     else {
       myEncryptMasterPasswordWithCheckBox.setSelected(false);
index 06898d4cef18da38dcdf47143cfb1bf2e557a37f..ccc4bcee5b4d85e679cef8fa5c0d50ac86ac2e08 100644 (file)
  */
 package com.intellij.ide.passwordSafe.ui;
 
+import com.intellij.ide.passwordSafe.PasswordSafe;
+import com.intellij.ide.passwordSafe.PasswordSafeException;
+import com.intellij.ide.passwordSafe.impl.PasswordSafeImpl;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.ui.DialogWrapper;
 import com.intellij.openapi.ui.Messages;
 import com.intellij.util.ui.UIUtil;
-import com.intellij.ide.passwordSafe.PasswordSafe;
-import com.intellij.ide.passwordSafe.PasswordSafeException;
-import com.intellij.ide.passwordSafe.impl.PasswordSafeImpl;
 
 import javax.swing.*;
 import java.util.concurrent.atomic.AtomicReference;
@@ -81,7 +81,7 @@ public class PasswordSafePromptDialog extends DialogWrapper {
         myRememberThePasswordCheckBox.setToolTipText("The password will be stored only during this application session.");
         break;
       case DO_NOT_STORE:
-        myRememberThePasswordCheckBox.setEnabled(true);
+        myRememberThePasswordCheckBox.setEnabled(false);
         myRememberThePasswordCheckBox.setSelected(false);
         myRememberThePasswordCheckBox.setToolTipText("The password storing is disabled.");
         break;
@@ -202,7 +202,7 @@ public class PasswordSafePromptDialog extends DialogWrapper {
                                      final String key,
                                      boolean resetPassword,
                                      String error) {
-    return askPassword(project, title, message, requester, key, resetPassword, error, "&Passphrase:", "&Remember the passphrase");
+    return askPassword(project, title, message, requester, key, resetPassword, error, "Passphrase:", "Remember the passphrase");
   }
 
   /**
@@ -235,8 +235,8 @@ public class PasswordSafePromptDialog extends DialogWrapper {
    * @param requester     the password requester
    * @param key           the password key
    * @param resetPassword if true, the old password is removed from database and new password will be asked.
-   * @param error
-   *@param promptLabel   the prompt label text
+   * @param error         the error text to show in the dialog
+   * @param promptLabel   the prompt label text
    * @param checkboxLabel the checkbox text   @return null if dialog was cancelled or password (stored in database or a entered by user)
    */
   private static String askPassword(final Project project,
index c240e8f48cb19b8dcde0031ef270ab51250245f3..06eaa824a9e94aaa3683ec79cdeb2445f1bc3e6e 100644 (file)
@@ -23,7 +23,6 @@ import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.ui.mac.foundation.Foundation;
 import com.intellij.ui.mac.foundation.ID;
 import com.sun.jna.Callback;
-import com.sun.jna.Pointer;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -39,7 +38,7 @@ public class MacFileChooserDialog implements FileChooserDialog {
   private static boolean myFileChooserActive = false;
 
   private static final Callback SHOULD_SHOW_FILENAME_CALLBACK = new Callback() {
-      public boolean callback(Pointer self, String selector, Pointer panel, Pointer filename) {
+      public boolean callback(ID self, String selector, ID panel, ID filename) {
         final String fileName = Foundation.toStringViaUTF8(filename);
         final VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(fileName);
         return virtualFile != null && (virtualFile.isDirectory() || getDescriptor().isFileSelectable(virtualFile));
@@ -47,7 +46,7 @@ public class MacFileChooserDialog implements FileChooserDialog {
     };
 
   private static final Callback IS_VALID_FILENAME_CALLBACK = new Callback() {
-      public boolean callback(Pointer self, String selector, Pointer panel, Pointer filename) {
+      public boolean callback(ID self, String selector, ID panel, ID filename) {
         final String fileName = Foundation.toStringViaUTF8(filename);
         final VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(fileName);
         return virtualFile != null && (!virtualFile.isDirectory() || getDescriptor().isFileSelectable(virtualFile));
@@ -55,7 +54,7 @@ public class MacFileChooserDialog implements FileChooserDialog {
     };
 
   static {
-    final Pointer delegateClass = Foundation.registerObjcClass(Foundation.getClass("NSObject"), "NSOpenPanelDelegate_");
+    final ID delegateClass = Foundation.registerObjcClass(Foundation.getClass("NSObject"), "NSOpenPanelDelegate_");
     if (!Foundation.addMethod(delegateClass, Foundation.createSelector("panel:shouldShowFilename:"), SHOULD_SHOW_FILENAME_CALLBACK, "B@:*"))
       throw new RuntimeException("Unable to add method to objective-c delegate class!");
     if (!Foundation.addMethod(delegateClass, Foundation.createSelector("panel:isValidFilename:"), IS_VALID_FILENAME_CALLBACK, "B@:*"))
@@ -81,13 +80,13 @@ public class MacFileChooserDialog implements FileChooserDialog {
 
     myFileChooserActive = true;
 
-    final Pointer autoReleasePool = createAutoReleasePool();
+    final ID autoReleasePool = createAutoReleasePool();
 
     try {
-      final Pointer chooser = invoke("NSOpenPanel", "openPanel");
+      final ID chooser = invoke("NSOpenPanel", "openPanel");
 
-      invoke(chooser, "setPrompt:", Foundation.cfString("Choose"));
       invoke(chooser, "autorelease");
+      invoke(chooser, "setPrompt:", Foundation.cfString("Choose"));
       invoke(chooser, "setCanChooseFiles:", myChooserDescriptor.isChooseFiles());
       invoke(chooser, "setCanChooseDirectories:", myChooserDescriptor.isChooseFolders());
       invoke(chooser, "setAllowsMultipleSelection:", myChooserDescriptor.isChooseMultiple());
@@ -95,20 +94,21 @@ public class MacFileChooserDialog implements FileChooserDialog {
         invoke(chooser, "_setIncludeNewFolderButton:", true);
       }
 
-      final Pointer delegate = invoke(Foundation.getClass("NSOpenPanelDelegate_"), "new");
+      final ID delegate = invoke(Foundation.getClass("NSOpenPanelDelegate_"), "new");
       invoke(chooser, "setDelegate:", delegate);
       
-      final Object directory = toSelect != null ? toSelect.isDirectory() ? Foundation.cfString(toSelect.getPath()).toLong() : null : null;
-      final Object file = toSelect != null ? !toSelect.isDirectory() ? Foundation.cfString(toSelect.getPath()).toLong() : null : null;
+      final Object directory = toSelect != null ? toSelect.isDirectory() ? Foundation.cfString(toSelect.getPath()) : null : null;
+      final Object file = toSelect != null ? !toSelect.isDirectory() ? Foundation.cfString(toSelect.getPath()) : null : null;
       final ID result = invoke(chooser, "runModalForDirectory:file:", directory, file);
-      if (result != null && OK == result.toInt()) {
+
+      if (result != null && OK == result.intValue()) {
         ID fileNamesArray = invoke(chooser, "filenames");
         ID enumerator = invoke(fileNamesArray, "objectEnumerator");
 
         final ArrayList<VirtualFile> fileNames = new ArrayList<VirtualFile>();
         while (true) {
           final ID filename = invoke(enumerator, "nextObject");
-          if (0 == filename.toInt()) break;
+          if (0 == filename.intValue()) break;
 
           String s = Foundation.toStringViaUTF8(filename);
           if (s != null) {
@@ -119,8 +119,6 @@ public class MacFileChooserDialog implements FileChooserDialog {
 
         return fileNames.toArray(new VirtualFile[fileNames.size()]);
       }
-
-      invoke(delegate, "release");
     }
     finally {
       invoke(autoReleasePool, "drain");
@@ -130,7 +128,7 @@ public class MacFileChooserDialog implements FileChooserDialog {
     return new VirtualFile[0];
   }
 
-  private static Pointer createAutoReleasePool() {
+  private static ID createAutoReleasePool() {
     return invoke("NSAutoreleasePool", "new");
   }
 
@@ -138,7 +136,7 @@ public class MacFileChooserDialog implements FileChooserDialog {
     return invoke(Foundation.getClass(className), selector, args);
   }
 
-  private static ID invoke(@NotNull final Pointer id, @NotNull final String selector, Object... args) {
+  private static ID invoke(@NotNull final ID id, @NotNull final String selector, Object... args) {
     return Foundation.invoke(id, Foundation.createSelector(selector), args);
   }
 }
index c9cda85a2fe37daf6269e01839325762c39e9036..68bc4caba8eeade350c1784c0872b8e483facc62 100644 (file)
  */
 package com.intellij.ui.mac.foundation;
 
-import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.util.containers.HashMap;
 import com.sun.jna.Callback;
-import com.sun.jna.Library;
 import com.sun.jna.Native;
 import com.sun.jna.Pointer;
 
@@ -29,8 +27,6 @@ import java.util.Map;
  * @author spleaner
  */
 public class Foundation {
-  private static final Logger LOG = Logger.getInstance("#com.intellij.ui.mac.foundation.Foundation");
-
   private static final FoundationLibrary myFoundationLibrary;
 
   static {
@@ -40,7 +36,7 @@ public class Foundation {
     System.setProperty("jna.encoding", "UTF8");
 
     Map<String, Object> foundationOptions = new HashMap<String, Object>();
-    foundationOptions.put(Library.OPTION_TYPE_MAPPER, FoundationTypeMapper.INSTANCE);
+    //foundationOptions.put(Library.OPTION_TYPE_MAPPER, FoundationTypeMapper.INSTANCE);
 
     myFoundationLibrary = (FoundationLibrary)Native.loadLibrary("Foundation", FoundationLibrary.class, foundationOptions);
   }
@@ -51,7 +47,7 @@ public class Foundation {
   /**
    * Get the ID of the NSClass with className
    */
-  public static Pointer getClass(String className) {
+  public static ID getClass(String className) {
     return myFoundationLibrary.objc_getClass(className);
   }
 
@@ -59,27 +55,23 @@ public class Foundation {
     return myFoundationLibrary.sel_registerName(s);
   }
 
-  public static ID invoke(final Pointer id, final Pointer selector, Object... args) {
+  public static ID invoke(final ID id, final Pointer selector, Object... args) {
     return myFoundationLibrary.objc_msgSend(id, selector, args);
   }
 
-  public static Pointer registerObjcClass(Pointer superCls, String name) {
+  public static ID registerObjcClass(ID superCls, String name) {
     return myFoundationLibrary.objc_allocateClassPair(superCls, name, 0);
   }
 
-  public static void registerObjcClassPair(Pointer cls) {
+  public static void registerObjcClassPair(ID cls) {
     myFoundationLibrary.objc_registerClassPair(cls);
   }
 
-  public static boolean isClassRespondsToSelector(Pointer cls, Pointer selectorName) {
+  public static boolean isClassRespondsToSelector(ID cls, Pointer selectorName) {
     return myFoundationLibrary.class_respondsToSelector(cls, selectorName);
   }
 
-  public static Pointer createClassInstance(Pointer cls) {
-    return myFoundationLibrary.class_createInstance(cls, 0);
-  }
-
-  public static boolean addMethod(Pointer cls, Pointer selectorName, Callback impl, String types) {
+  public static boolean addMethod(ID cls, Pointer selectorName, Callback impl, String types) {
     return myFoundationLibrary.class_addMethod(cls, selectorName, impl, types);
   }
 
@@ -92,7 +84,7 @@ public class Foundation {
    * <p/>
    * Note that the returned string must be freed with {@link #cfRelease(ID)}.
    */
-  public static ID cfString(String s) {
+  public static Pointer cfString(String s) {
     // Use a byte[] rather than letting jna do the String -> char* marshalling itself.
     // Turns out about 10% quicker for long strings.
     try {
@@ -105,7 +97,7 @@ public class Foundation {
     }
   }
 
-  public static String toStringViaUTF8(Pointer cfString) {
+  public static String toStringViaUTF8(ID cfString) {
     int lengthInChars = myFoundationLibrary.CFStringGetLength(cfString);
     int potentialLengthInBytes = 3 * lengthInChars + 1; // UTF8 fully escaped 16 bit chars, plus nul
 
@@ -114,12 +106,4 @@ public class Foundation {
     if (ok == 0) throw new RuntimeException("Could not convert string");
     return Native.toString(buffer);
   }
-
-  public static void cfRetain(final Pointer id) {
-    myFoundationLibrary.CFRetain(id);
-  }
-
-  public static void cfRelease(final Pointer id) {
-    myFoundationLibrary.CFRelease(id);
-  }
 }
index 67cfead9a3d6028234e0c2f5c2e81ae9b0fddcf5..6319d9bced129f9ff7f470467b7f010a8a00847d 100644 (file)
@@ -18,7 +18,6 @@ package com.intellij.ui.mac.foundation;
 import com.sun.jna.Callback;
 import com.sun.jna.Library;
 import com.sun.jna.Pointer;
-import com.sun.jna.Structure;
 
 /**
  * @author spleaner
@@ -26,30 +25,25 @@ import com.sun.jna.Structure;
 public interface FoundationLibrary extends Library {
   void NSLog(Pointer pString, Object thing);
 
-  Pointer objc_allocateClassPair(Pointer supercls, String name, int extraBytes);
-  void objc_registerClassPair(Pointer cls);
+  ID objc_allocateClassPair(ID supercls, String name, int extraBytes);
+  void objc_registerClassPair(ID cls);
 
-  ID CFStringCreateWithCString(Pointer allocator, String string, int encoding);
-  ID CFStringCreateWithBytes(Pointer allocator, byte[] bytes, int byteCount, int encoding, byte isExternalRepresentation);
-  String CFStringGetCStringPtr(Pointer string, int encoding);
-  byte CFStringGetCString(Pointer theString, byte[] buffer, int bufferSize, int encoding);
-  int CFStringGetLength(Pointer theString);
+  Pointer CFStringCreateWithBytes(Pointer allocator, byte[] bytes, int byteCount, int encoding, byte isExternalRepresentation);
+  byte CFStringGetCString(ID theString, byte[] buffer, int bufferSize, int encoding);
+  int CFStringGetLength(ID theString);
 
   void CFRetain(Pointer cfTypeRef);
   void CFRelease(Pointer cfTypeRef);
   int CFGetRetainCount (Pointer cfTypeRef);
 
-  Pointer objc_getClass(String className);
-  Pointer class_createInstance(Pointer pClass, int extraBytes);
+  ID objc_getClass(String className);
+  ID class_createInstance(ID pClass, int extraBytes);
   Pointer sel_registerName(String selectorName);
 
-  ID objc_msgSend(Pointer receiver, Pointer selector, Object... args);
-  Structure objc_msgSend_stret(Pointer receiver, Pointer selector, Object... args);
+  ID objc_msgSend(ID receiver, Pointer selector, Object... args);
 
-  boolean class_respondsToSelector(Pointer cls, Pointer selName);
-
-  boolean class_addMethod(Pointer cls, Pointer selName, Callback imp, String types);
-  boolean class_replaceMethod(Pointer cls, Pointer selName, Callback imp, String types);
+  boolean class_respondsToSelector(ID cls, Pointer selName);
+  boolean class_addMethod(ID cls, Pointer selName, Callback imp, String types);
 
   Pointer objc_getClass(Pointer clazz);
 }
diff --git a/platform/platform-impl/src/com/intellij/ui/mac/foundation/FoundationTypeMapper.java b/platform/platform-impl/src/com/intellij/ui/mac/foundation/FoundationTypeMapper.java
deleted file mode 100644 (file)
index 2a37309..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2000-2010 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.intellij.ui.mac.foundation;
-
-import com.sun.jna.*;
-
-/**
- * @author spleaner
- */
-public class FoundationTypeMapper extends DefaultTypeMapper {
-
-  public static final FoundationTypeMapper INSTANCE = new FoundationTypeMapper();
-
-  private static final ToNativeConverter myToNativeConverter = new IDtoConverter();
-  private static final FromNativeConverter myFromNativeConverter = new IDFromConverter();
-
-  @Override
-  public FromNativeConverter getFromNativeConverter(Class javaType) {
-    if (javaType == ID.class) return myFromNativeConverter;
-    return super.getFromNativeConverter(javaType);
-  }
-
-  @Override
-  public ToNativeConverter getToNativeConverter(Class javaType) {
-    if (javaType == ID.class) return myToNativeConverter;
-    return  super.getToNativeConverter(javaType);
-  }
-
-  static class IDFromConverter implements FromNativeConverter {
-    public Object fromNative(Object o, FromNativeContext fromNativeContext) {
-      return new ID((Long) o);
-    }
-
-    public Class nativeType() {
-      return Long.TYPE;
-    }
-  }
-
-  static class IDtoConverter implements ToNativeConverter {
-    public Object toNative(Object o, ToNativeContext toNativeContext) {
-      if (o != null) {
-        return ((ID)o).getAddress();
-      } else {
-        return new Long(0);
-      }
-    }
-
-    public Class nativeType() {
-      return Long.TYPE;
-    }
-  }
-}
index b98cfeabbade4a3791a1a234c26ca61f9744931f..9665c3716570c2d245b015a621bde6fcbdc1878a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2010 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  */
 package com.intellij.ui.mac.foundation;
 
-import com.sun.jna.Pointer;
+import com.sun.jna.NativeLong;
 
 /**
- * @author spleaner
+ * Could be an address in memory (if pointer to a class or method) or a value (like 0 or 1)
+ *
+ * User: spLeaner
  */
-public class ID extends Pointer {
-  public ID(long peer) {
-    super(peer);
-  }
+public class ID extends NativeLong {
 
-  public long toLong() {
-    return peer;
-  }
-  
-  public int toInt() {
-    return (int) peer;
+  public ID() {
   }
 
-  public long getAddress() {
-    return peer;
+  public ID(long peer) {
+    super(peer);
   }
+
 }
index 2329a744cde7924c2f3470be0e3cd8293c36526c..8198247e6c0220256d1d3763cd3a8ce0f0fc3215 100644 (file)
@@ -15,6 +15,7 @@
  */
 package com.intellij.ui.mac.growl;
 
+import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.ui.mac.foundation.Foundation;
 import com.intellij.ui.mac.foundation.ID;
 import com.sun.jna.Pointer;
@@ -24,6 +25,8 @@ import org.jetbrains.annotations.NotNull;
  * @author spleaner
  */
 public class Growl {
+  private static final Logger LOG = Logger.getInstance("#com.intellij.ui.mac.Growl");
+
   private static final String GROWL_APPLICATION_REGISTRATION_NOTIFICATION = "GrowlApplicationRegistrationNotification";
   private static final String GROWL_APP_NAME = "ApplicationName";
   private static final String GROWL_APP_ICON = "ApplicationIcon";
@@ -43,29 +46,26 @@ public class Growl {
   }
 
   public void register() {
-    final Pointer autoReleasePool = createAutoReleasePool();
-    final Pointer applicationIcon = getApplicationIcon();
-
-    final Pointer defaultNotifications = fillArray(myDefaultNotification);
-    final Pointer allNotifications = fillArray(myAllNotifications);
+    final ID autoReleasePool = createAutoReleasePool();
+    final ID applicationIcon = getApplicationIcon();
+    final ID defaultNotifications = fillArray(myDefaultNotification);
+    final ID allNotifications = fillArray(myAllNotifications);
 
-    final Pointer userDict = createDict(new String[]{GROWL_APP_NAME, GROWL_APP_ICON, GROWL_DEFAULT_NOTIFICATIONS, GROWL_ALL_NOTIFICATIONS},
+    final ID userDict = createDict(new String[]{GROWL_APP_NAME, GROWL_APP_ICON, GROWL_DEFAULT_NOTIFICATIONS, GROWL_ALL_NOTIFICATIONS},
         new Object[]{myProductName, applicationIcon, defaultNotifications, allNotifications});
 
-    final Pointer center = invoke("NSDistributedNotificationCenter", "defaultCenter");
+    final ID center = invoke("NSDistributedNotificationCenter", "defaultCenter");
     final Object notificationName = Foundation.cfString(GROWL_APPLICATION_REGISTRATION_NOTIFICATION);
     invoke(center, "postNotificationName:object:userInfo:deliverImmediately:", notificationName, null, userDict, true);
-
     invoke(autoReleasePool, "release");
   }
 
   public void notifyGrowlOf(final String notification, final String title, final String description) {
-    final Pointer autoReleasePool = createAutoReleasePool();
-
-    final Pointer dict = createDict(new String[]{
+    final ID autoReleasePool = createAutoReleasePool();
+    final ID dict = createDict(new String[]{
         GROWL_NOTIFICATION_NAME, GROWL_NOTIFICATION_TITLE, GROWL_NOTIFICATION_DESCRIPTION, GROWL_APP_NAME},
         new Object[]{notification, title, description, myProductName});
-    final Pointer center = invoke("NSDistributedNotificationCenter", "defaultCenter");
+    final ID center = invoke("NSDistributedNotificationCenter", "defaultCenter");
     final Object notificationName = Foundation.cfString(GROWL_NOTIFICATION);
 
     invoke(center, "postNotificationName:object:userInfo:deliverImmediately:", notificationName, null, dict, true);
@@ -80,12 +80,12 @@ public class Growl {
     myDefaultNotification = defaultNotification;
   }
 
-  private static Pointer createAutoReleasePool() {
+  private static ID createAutoReleasePool() {
     return invoke("NSAutoreleasePool", "new");
   }
 
-  private static Pointer fillArray(final Object[] a) {
-    final Pointer result = invoke("NSMutableArray", "array");
+  private static ID fillArray(final Object[] a) {
+    final ID result = invoke("NSMutableArray", "array");
     for (Object s : a) {
       invoke(result, "addObject:", convertType(s));
     }
@@ -93,15 +93,15 @@ public class Growl {
     return result;
   }
 
-  private static Pointer createDict(@NotNull final String[] keys, @NotNull final Object[] values) {
-    final Pointer nsKeys = invoke("NSArray", "arrayWithObjects:", convertTypes(keys));
-    final Pointer nsData = invoke("NSArray", "arrayWithObjects:", convertTypes(values));
+  private static ID createDict(@NotNull final String[] keys, @NotNull final Object[] values) {
+    final ID nsKeys = invoke("NSArray", "arrayWithObjects:", convertTypes(keys));
+    final ID nsData = invoke("NSArray", "arrayWithObjects:", convertTypes(values));
 
     return invoke("NSDictionary", "dictionaryWithObjects:forKeys:", nsData, nsKeys);
   }
 
   private static Object convertType(final Object o) {
-    if (o instanceof ID) {
+    if (o instanceof Pointer || o instanceof ID) {
       return o;
     } else if (o instanceof String) {
       return Foundation.cfString((String) o);
@@ -119,21 +119,21 @@ public class Growl {
     return result;
   }
 
-  private static Pointer getApplicationIcon() {
-    final Pointer sharedApp = invoke("NSApplication", "sharedApplication");
-    final Pointer nsImage = invoke(sharedApp, "applicationIconImage");
+  private static ID getApplicationIcon() {
+    final ID sharedApp = invoke("NSApplication", "sharedApplication");
+    final ID nsImage = invoke(sharedApp, "applicationIconImage");
     return invoke(nsImage, "TIFFRepresentation");
   }
 
-  private static Pointer invoke(@NotNull final String className, @NotNull final String selector, Object... args) {
+  private static ID invoke(@NotNull final String className, @NotNull final String selector, Object... args) {
     return invoke(Foundation.getClass(className), selector, args);
   }
 
-  private static Pointer invoke(@NotNull final Pointer id, @NotNull final String selector, Object... args) {
+  private static ID invoke(@NotNull final ID id, @NotNull final String selector, Object... args) {
     return invoke(id, Foundation.createSelector(selector), args);
   }
 
-  private static Pointer invoke(@NotNull final Pointer id, @NotNull final Pointer selector, Object... args) {
+  private static ID invoke(@NotNull final ID id, @NotNull final Pointer selector, Object... args) {
     return Foundation.invoke(id, selector, args);
   }
 }
diff --git a/platform/platform-impl/testSrc/com/intellij/ide/passwordSafe/impl/providers/masterKey/MasterKeyPasswordSafeTest.java b/platform/platform-impl/testSrc/com/intellij/ide/passwordSafe/impl/providers/masterKey/MasterKeyPasswordSafeTest.java
new file mode 100644 (file)
index 0000000..973d54e
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.ide.passwordSafe.impl.providers.masterKey;
+
+import com.intellij.ide.passwordSafe.PasswordSafeException;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * The test for master key password safe
+ */
+public class MasterKeyPasswordSafeTest {
+
+  @Test
+  public void testMasterKey() throws PasswordSafeException {
+    PasswordDatabase db = new PasswordDatabase();
+    MasterKeyPasswordSafe s1 = testProvider(db);
+    s1.resetMasterPassword("pass1", false);
+    s1.storePassword(null, MasterKeyPasswordSafeTest.class, "TEST", "test");
+    assertEquals("test", s1.getPassword(null, MasterKeyPasswordSafeTest.class, "TEST"));
+    assertTrue(s1.changeMasterPassword("pass1", "pass2", false));
+    assertEquals("test", s1.getPassword(null, MasterKeyPasswordSafeTest.class, "TEST"));
+    MasterKeyPasswordSafe s2 = testProvider(db);
+    assertFalse(s2.setMasterPassword("pass1"));
+    assertTrue(s2.setMasterPassword("pass2"));
+    assertEquals("test", s2.getPassword(null, MasterKeyPasswordSafeTest.class, "TEST"));
+    assertTrue(s2.changeMasterPassword("pass2", "pass3", false));
+    assertTrue(s2.changeMasterPassword("pass3", "pass4", false));
+    assertTrue(s2.setMasterPassword("pass4"));
+    assertEquals("test", s2.getPassword(null, MasterKeyPasswordSafeTest.class, "TEST"));
+    s2.resetMasterPassword("fail", false);
+    assertNull(s2.getPassword(null, MasterKeyPasswordSafeTest.class, "TEST"));
+  }
+
+  /**
+   * Get test instance of the provider
+   * @param db the database to use
+   * @return a instance of the provider
+   */
+  private static MasterKeyPasswordSafe testProvider(final PasswordDatabase db) {
+    return new MasterKeyPasswordSafe(db) {
+      protected boolean isTestMode() {
+        return true;
+      }
+    };
+  }
+
+}
index f56be2403ff80864e9f0f23f028e3278af5d75d8..9b27acfb3e0f0a15bec4692641c7bbd0ebb29672 100644 (file)
@@ -279,6 +279,25 @@ public class CharArrayUtil {
     return indexOf(buffer, pattern, fromIndex, buffer.length());
   }
 
+  /**
+   * Tries to find index of given pattern at the given buffer.
+   * <p/>
+   * <b>Note:</b> given <code>'toIndex'</code> value restricts examination to <code>'toIndex -1'</code> value (exclusive).. I.e. invocation like below
+   * doesn't find the match:
+   * <pre>
+   *        String buffer = "aab";
+   *        String pattern = "ab";
+   *        CharArrayUtil.indexOf(buffer, pattern, 0, buffer.length()); // right boundary is "aab".length() - 1 = 2 (exclusive)
+   * </pre>
+   * <p/>
+   * This is historical behavior and is not going to be changed in order to preserve backward compatibility.
+   *
+   * @param buffer          characters buffer which contents should be checked for the given pattern
+   * @param pattern         target characters sequence to find at the given buffer
+   * @param fromIndex    start index (inclusive). Zero is used if given index is negative
+   * @param toIndex        defines end index (exclusive) by the formula <code>'toIndex - 1'</code>
+   * @return                    index of the given pattern at the given buffer if the match is found; <code>-1</code> otherwise
+   */
   public static int indexOf(final CharSequence buffer, final CharSequence pattern, int fromIndex, final int toIndex) {
     final int patternLength = pattern.length();
     int limit = toIndex - patternLength;
index 99bba82f56a7805ca45a22f0821c6d6c98cdf2c2..eca26d8ac630c10fec8346ccb0aaa7e41076d381 100644 (file)
@@ -19,6 +19,8 @@
     <orderEntry type="module" module-name="properties" />
     <orderEntry type="module" module-name="execution-openapi" />
     <orderEntry type="module" module-name="idea-ui" />
+    <orderEntry type="module" module-name="dom-openapi" />
+    <orderEntry type="module" module-name="xml-openapi" />
   </component>
   <component name="copyright">
     <Base>
diff --git a/plugins/ant/src/com/intellij/lang/ant/dom/AntDomElement.java b/plugins/ant/src/com/intellij/lang/ant/dom/AntDomElement.java
new file mode 100644 (file)
index 0000000..f464250
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.lang.ant.dom;
+
+import com.intellij.util.xml.DomElement;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Apr 6, 2010
+ */
+public interface AntDomElement extends DomElement {
+}
diff --git a/plugins/ant/src/com/intellij/lang/ant/dom/AntDomFileDescription.java b/plugins/ant/src/com/intellij/lang/ant/dom/AntDomFileDescription.java
new file mode 100644 (file)
index 0000000..3b28b66
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.lang.ant.dom;
+
+import com.intellij.lang.ant.AntLanguageExtension;
+import com.intellij.openapi.module.Module;
+import com.intellij.psi.xml.XmlFile;
+import com.intellij.psi.xml.XmlTag;
+import com.intellij.util.xml.DomFileDescription;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Apr 6, 2010
+ */
+public class AntDomFileDescription extends DomFileDescription<AntDomProject> {
+  public AntDomFileDescription() {
+    super(AntDomProject.class, "project");
+  }
+
+  protected void initializeFileDescription() {
+    // todo
+  }
+
+  public boolean isMyFile(@NotNull XmlFile file, @Nullable Module module) {
+    return super.isMyFile(file, module) && AntLanguageExtension.isAntFile(file);
+  }
+
+}
diff --git a/plugins/ant/src/com/intellij/lang/ant/dom/AntDomProject.java b/plugins/ant/src/com/intellij/lang/ant/dom/AntDomProject.java
new file mode 100644 (file)
index 0000000..d6b795e
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.lang.ant.dom;
+
+import com.intellij.util.xml.Attribute;
+import com.intellij.util.xml.GenericAttributeValue;
+import com.intellij.util.xml.SubTagList;
+
+import java.util.List;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Apr 6, 2010
+ */
+public interface AntDomProject extends AntDomElement {
+
+  @Attribute("name")
+  GenericAttributeValue<String> getName();
+
+  @Attribute("default")
+  GenericAttributeValue<String> getDefaultTargetName();
+
+  @Attribute("basedir")
+  GenericAttributeValue<String> getBasedir();
+
+  @SubTagList("target")
+  List<AntTarget> getTargets();
+}
diff --git a/plugins/ant/src/com/intellij/lang/ant/dom/AntTarget.java b/plugins/ant/src/com/intellij/lang/ant/dom/AntTarget.java
new file mode 100644 (file)
index 0000000..7b48df8
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.lang.ant.dom;
+
+import com.intellij.util.xml.Attribute;
+import com.intellij.util.xml.GenericAttributeValue;
+import com.intellij.util.xml.SubTagList;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Apr 6, 2010
+ */
+public interface AntTarget extends AntDomElement{
+  @Attribute("name")
+  GenericAttributeValue<String> getName();
+
+  @Attribute("if")
+  GenericAttributeValue<String> getIfPropertyName();
+
+  @Attribute("unless")
+  GenericAttributeValue<String> getUnlessPropertyName();
+}
diff --git a/plugins/ant/src/com/intellij/lang/ant/dom/AntTask.java b/plugins/ant/src/com/intellij/lang/ant/dom/AntTask.java
new file mode 100644 (file)
index 0000000..2ac9a90
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.lang.ant.dom;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Apr 6, 2010
+ */
+public interface AntTask extends AntDomElement{
+}
index 26248ec68c3d1ac3b3835b3ccf187e858eb3fd16..26aa44af67435dad1535f54f84f8a5430d35af2b 100644 (file)
@@ -31,7 +31,6 @@ import com.intellij.lang.ant.psi.introspection.AntAttributeType;
 import com.intellij.lang.ant.psi.introspection.AntTypeDefinition;
 import com.intellij.lang.ant.psi.introspection.AntTypeId;
 import com.intellij.lang.ant.psi.introspection.impl.AntTypeDefinitionImpl;
-import com.intellij.openapi.application.ModalityState;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.fileTypes.FileType;
 import com.intellij.openapi.fileTypes.StdFileTypes;
@@ -49,7 +48,6 @@ import com.intellij.psi.xml.XmlAttribute;
 import com.intellij.psi.xml.XmlDocument;
 import com.intellij.psi.xml.XmlFile;
 import com.intellij.psi.xml.XmlTag;
-import com.intellij.util.Alarm;
 import com.intellij.util.LocalTimeCounter;
 import com.intellij.util.Processor;
 import com.intellij.util.StringBuilderSpinAllocator;
@@ -1003,7 +1001,6 @@ public class AntFileImpl extends LightPsiFileBase implements AntFile {
 
     private static final List<SoftReference<Pair<ReflectedProject, ClassLoader>>> ourProjects =
       new ArrayList<SoftReference<Pair<ReflectedProject, ClassLoader>>>();
-    private static final Alarm ourAlarm = new Alarm();
 
     private final Object myProject;
     private Hashtable myTaskDefinitions;
@@ -1012,38 +1009,23 @@ public class AntFileImpl extends LightPsiFileBase implements AntFile {
     private Class myTargetClass;
 
     private static ReflectedProject getProject(final ClassLoader classLoader) {
-      try {
-        synchronized (ourProjects) {
-          for (final SoftReference<Pair<ReflectedProject, ClassLoader>> ref : ourProjects) {
-            final Pair<ReflectedProject, ClassLoader> pair = ref.get();
-            if (pair != null && pair.second == classLoader) {
-              return pair.first;
-            }
-          }
-          ReflectedProject project = new ReflectedProject(classLoader);
-          final SoftReference<Pair<ReflectedProject, ClassLoader>> ref =
-            new SoftReference<Pair<ReflectedProject, ClassLoader>>(new Pair<ReflectedProject, ClassLoader>(project, classLoader));
-          for (int i = 0; i < ourProjects.size(); ++i) {
-            final Pair<ReflectedProject, ClassLoader> pair = ourProjects.get(i).get();
-            if (pair == null) {
-              ourProjects.set(i, ref);
-              return project;
-            }
-          }
-          ourProjects.add(ref);
-          return project;
+      for (Iterator<SoftReference<Pair<ReflectedProject, ClassLoader>>> iterator = ourProjects.iterator(); iterator.hasNext();) {
+        final SoftReference<Pair<ReflectedProject, ClassLoader>> ref = iterator.next();
+        final Pair<ReflectedProject, ClassLoader> pair = ref.get();
+        if (pair == null) {
+          iterator.remove();
         }
-      }
-      finally {
-        ourAlarm.cancelAllRequests();
-        ourAlarm.addRequest(new Runnable() {
-          public void run() {
-            synchronized (ourProjects) {
-              ourProjects.clear();
-            }
+        else {
+          if (pair.second == classLoader) {
+            return pair.first;
           }
-        }, 30000, ModalityState.NON_MODAL);
+        }
       }
+      final ReflectedProject project = new ReflectedProject(classLoader);
+      ourProjects.add(new SoftReference<Pair<ReflectedProject, ClassLoader>>(
+        new Pair<ReflectedProject, ClassLoader>(project, classLoader)
+      ));
+      return project;
     }
 
     private ReflectedProject(final ClassLoader classLoader) {
index 3475489741383884204ab4cbf1b481a195f7ca5c..92ee3727b1972aacc57a2acb4fdce49a23a150f5 100644 (file)
@@ -113,11 +113,13 @@ public class GitPushActiveBranchesDialog extends DialogWrapper {
     TreeUtil.expandAll(myCommitTree);
     final GitVcsSettings settings = GitVcsSettings.getInstance(project);
     UpdatePolicyUtils.updatePolicyItem(settings.PUSH_ACTIVE_BRANCHES_REBASE_SAVE_POLICY, myStashRadioButton, myShelveRadioButton, null);
-    myStashRadioButton.addChangeListener(new ChangeListener() {
+    ChangeListener listener = new ChangeListener() {
       public void stateChanged(ChangeEvent e) {
         settings.PUSH_ACTIVE_BRANCHES_REBASE_SAVE_POLICY = UpdatePolicyUtils.getUpdatePolicy(myStashRadioButton, myShelveRadioButton, null);
       }
-    });
+    };
+    myStashRadioButton.addChangeListener(listener);
+    myShelveRadioButton.addChangeListener(listener);
     myCommitTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
       public void valueChanged(TreeSelectionEvent e) {
         TreePath path = myCommitTree.getSelectionModel().getSelectionPath();
index c9ae3335026f94e1a0196eca050ef4a7e8e063dd..a14908dc40bd3242677ca396dce43548f564a9cb 100644 (file)
@@ -2,7 +2,7 @@
   <id>org.intellij.groovy.hotswap</id>
   <name>Groovy HotSwap</name>
   <description>Enables HotSwap functionality in Groovy classes</description>
-  <version>0.5</version>
+  <version>0.6</version>
   <idea-version since-build="94.632" until-build="96.1"/>
   <vendor logo="/org/jetbrains/plugins/groovy/images/groovy_16x16.png" url="http://www.jetbrains.com">JetBrains Inc.</vendor>
   <depends>org.intellij.groovy</depends>
index 77e40b67f901d3ed00a340cc6e2674a509ad7b57..a1cccf8e60a6c2a3ffb535f95eec8049703afd70 100644 (file)
@@ -6,15 +6,20 @@ import com.intellij.execution.configurations.RunConfiguration;
 import com.intellij.execution.configurations.RunProfile;
 import com.intellij.execution.executors.DefaultDebugExecutor;
 import com.intellij.execution.runners.JavaProgramPatcher;
+import com.intellij.openapi.application.PathManager;
 import com.intellij.openapi.application.PluginPathManager;
+import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.roots.LanguageLevelProjectExtension;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.openapi.util.io.FileUtil;
 import com.intellij.pom.java.LanguageLevel;
 import com.intellij.psi.search.FilenameIndex;
 import com.intellij.util.PathUtil;
 import org.jetbrains.plugins.groovy.GroovyFileTypeLoader;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -23,6 +28,7 @@ import java.util.List;
  * @author peter
  */
 public class GroovyHotSwapper extends JavaProgramPatcher {
+  private static final Logger LOG = Logger.getInstance("#org.jetbrains.plugins.groovy.debugger.GroovyHotSwapper");
 
   private static boolean endsWithAny(String s, List<String> endings) {
     for (String extension : endings) {
@@ -68,10 +74,25 @@ public class GroovyHotSwapper extends JavaProgramPatcher {
     }
 
     if (containsGroovyClasses(project)) {
-      javaParameters.getVMParametersList().add("-javaagent:" + getAgentJarPath());
+      javaParameters.getVMParametersList().add("-javaagent:" + handleSpacesInPath(getAgentJarPath()));
     }
   }
 
+  private static String handleSpacesInPath(String agentPath) {
+    if (SystemInfo.isUnix && agentPath.contains(" ")) {
+      final File dir = new File(PathManager.getSystemPath(), "groovyHotSwap");
+      final File toFile = new File(dir, "gragent.jar");
+      try {
+        FileUtil.copy(new File(agentPath), toFile);
+        return toFile.getPath();
+      }
+      catch (IOException e) {
+        LOG.info(e);
+      }
+    }
+    return agentPath;
+  }
+
   private static String getAgentJarPath() {
     final File ourJar = new File(PathUtil.getJarPathForClass(GroovyHotSwapper.class));
     if (ourJar.isDirectory()) { //development mode
index fc178e8e9f4a3a1ae066a29e42f6970e94ebe052..c1cf97b5403b6b2956263562faf268f2201c5cb6 100644 (file)
@@ -40,7 +40,7 @@ public class StandardDslIndexedRootsProvider implements IndexedRootsProvider {
     }
 
     final VirtualFile parent = LocalFileSystem.getInstance().refreshAndFindFileByPath(dirPath);
-    assert parent != null;
+    assert parent != null : dirPath;
     parent.getChildren();
     ourDslsDir = parent.getUrl();
     parent.refresh(true, true);
index 3bf92840409e925b7cdd56e13f8841579ce1046a..98bbd653767ae91894b530ee25118d56d29e2e50 100644 (file)
@@ -15,7 +15,6 @@
  */
 package org.jetbrains.plugins.groovy.lang.psi.impl.search;
 
-import com.intellij.openapi.fileTypes.FileType;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.roots.ProjectFileIndex;
@@ -39,9 +38,7 @@ public class GrSourceFilterScope extends GlobalSearchScope {
   }
 
   public boolean contains(final VirtualFile file) {
-    final FileType fileType = file.getFileType();
-    return (myDelegate == null || myDelegate.contains(file)) &&
-            GroovyFileType.GROOVY_FILE_TYPE == fileType && myIndex.isInSourceContent(file);
+    return (myDelegate == null || myDelegate.contains(file)) && myIndex.isInSourceContent(file) && GroovyFileType.GROOVY_FILE_TYPE == file.getFileType();
     }
     
   public int compare(final VirtualFile file1, final VirtualFile file2) {
diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenArtifactScope.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenArtifactScope.java
new file mode 100644 (file)
index 0000000..4fef212
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.idea.maven.utils;
+
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Konstantin Bulenkov
+ */
+public enum MavenArtifactScope {
+  COMPILE, PROVIDEED, RUNTIME, TEST, SYSTEM, IMPORT;
+
+  @Nullable
+  public static MavenArtifactScope fromString(String name) {
+    for (MavenArtifactScope scope : MavenArtifactScope.values()) {
+      if (scope.name().equalsIgnoreCase(name)) return scope;
+    }
+    return null;
+  }
+}