Cleanup (formatting; minor fixes; API usability)
authorRoman Shevchenko <roman.shevchenko@jetbrains.com>
Mon, 12 Jan 2015 16:24:42 +0000 (17:24 +0100)
committerRoman Shevchenko <roman.shevchenko@jetbrains.com>
Wed, 14 Jan 2015 11:50:04 +0000 (12:50 +0100)
platform/lang-api/src/com/intellij/openapi/projectRoots/ui/PathEditor.java
platform/lang-impl/src/com/intellij/openapi/roots/impl/ProjectRootManagerComponent.java
platform/platform-api/src/com/intellij/openapi/vfs/newvfs/ArchiveFileSystem.java
platform/platform-api/src/com/intellij/util/io/HttpRequests.java
platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarFileSystemImpl.java
platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemImpl.java
platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/VfsImplUtil.java

index ae9f0142f246d90fce3314156e372a3880125172..dd641541924987c6ff555f0cd73631483c4681f4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2015 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.
@@ -26,10 +26,7 @@ import com.intellij.openapi.fileChooser.FileChooserDescriptor;
 import com.intellij.openapi.fileTypes.FileTypes;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.Computable;
-import com.intellij.openapi.vfs.JarFileSystem;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import com.intellij.openapi.vfs.VfsUtil;
-import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.*;
 import com.intellij.openapi.vfs.ex.http.HttpFileSystem;
 import com.intellij.ui.*;
 import com.intellij.ui.components.JBList;
@@ -111,33 +108,36 @@ public class PathEditor {
     myList = new JBList(getListModel());
     myList.setCellRenderer(createListCellRenderer(myList));
 
-    ToolbarDecorator toolbarDecorator = ToolbarDecorator.createDecorator(myList).disableUpDownActions()
+    ToolbarDecorator toolbarDecorator = ToolbarDecorator.createDecorator(myList)
+      .disableUpDownActions()
+      .setAddActionUpdater(new AnActionButtonUpdater() {
+        @Override
+        public boolean isEnabled(AnActionEvent e) {
+          return myEnabled;
+        }
+      })
+      .setRemoveActionUpdater(new AnActionButtonUpdater() {
+        @Override
+        public boolean isEnabled(AnActionEvent e) {
+          return isRemoveActionEnabled(PathEditor.this.getSelectedRoots());
+        }
+      })
       .setAddAction(new AnActionButtonRunnable() {
         @Override
         public void run(AnActionButton button) {
-          final VirtualFile[] added = doAdd();
+          final VirtualFile[] added = doAddItems();
           if (added.length > 0) {
             setModified(true);
           }
           requestDefaultFocus();
           setSelectedRoots(added);
         }
-      }).setRemoveAction(new AnActionButtonRunnable() {
+      })
+      .setRemoveAction(new AnActionButtonRunnable() {
         @Override
         public void run(AnActionButton button) {
-          int[] idxs = myList.getSelectedIndices();
-          doRemoveItems(idxs, myList);
-        }
-      }).setAddActionUpdater(new AnActionButtonUpdater() {
-        @Override
-        public boolean isEnabled(AnActionEvent e) {
-          return myEnabled;
-        }
-      }).setRemoveActionUpdater(new AnActionButtonUpdater() {
-        @Override
-        public boolean isEnabled(AnActionEvent e) {
-          Object[] values = getSelectedRoots();
-          return values.length > 0 && myEnabled;
+          int[] indices = myList.getSelectedIndices();
+          doRemoveItems(indices, myList);
         }
       });
 
@@ -152,8 +152,25 @@ public class PathEditor {
   protected void addToolbarButtons(ToolbarDecorator toolbarDecorator) {
   }
 
-  protected void doRemoveItems(int[] idxs, JList list) {
-    List removedItems = ListUtil.removeIndices(list, idxs);
+  protected boolean isRemoveActionEnabled(Object[] values) {
+    return values.length > 0 && myEnabled;
+  }
+
+  protected VirtualFile[] doAddItems() {
+    Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(myPanel));
+    VirtualFile[] files = FileChooser.chooseFiles(myDescriptor, myPanel, project, myAddBaseDir);
+    files = adjustAddedFileSet(myPanel, files);
+    List<VirtualFile> added = new ArrayList<VirtualFile>(files.length);
+    for (VirtualFile vFile : files) {
+      if (addElement(vFile)) {
+        added.add(vFile);
+      }
+    }
+    return VfsUtilCore.toVirtualFileArray(added);
+  }
+
+  protected void doRemoveItems(int[] indices, JList list) {
+    List removedItems = ListUtil.removeIndices(list, indices);
     itemsRemoved(removedItems);
   }
 
@@ -162,7 +179,7 @@ public class PathEditor {
   }
 
   protected ListCellRenderer createListCellRenderer(JBList list) {
-    return new MyCellRenderer();
+    return new PathCellRenderer();
   }
 
   protected void itemsRemoved(List removedItems) {
@@ -173,19 +190,6 @@ public class PathEditor {
     requestDefaultFocus();
   }
 
-  protected VirtualFile[] doAdd() {
-    Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(myPanel));
-    VirtualFile[] files = FileChooser.chooseFiles(myDescriptor, myPanel, project, myAddBaseDir);
-    files = adjustAddedFileSet(myPanel, files);
-    List<VirtualFile> added = new ArrayList<VirtualFile>(files.length);
-    for (VirtualFile vFile : files) {
-      if (addElement(vFile)) {
-        added.add(vFile);
-      }
-    }
-    return VfsUtil.toVirtualFileArray(added);
-  }
-
   /**
    * Implement this method to adjust adding behavior, this method is called right after the files
    * or directories are selected for added. This method allows adding UI that modify file set.
@@ -284,17 +288,18 @@ public class PathEditor {
 
   private void keepSelectionState() {
     final Object[] selectedItems = getSelectedRoots();
-
-    SwingUtilities.invokeLater(new Runnable() {
-      @Override
-      public void run() {
-        if (selectedItems != null) {
+    if (selectedItems != null) {
+      //noinspection SSBasedInspection
+      SwingUtilities.invokeLater(new Runnable() {
+        @Override
+        public void run() {
           setSelectedRoots(selectedItems);
         }
-      }
-    });
+      });
+    }
   }
 
+  @SuppressWarnings("deprecation")
   protected Object[] getSelectedRoots() {
     return myList.getSelectedValues();
   }
@@ -332,59 +337,46 @@ public class PathEditor {
     }).booleanValue();
   }
 
-  /**
-   * @return icon for displaying parameter (ProjectRoot or VirtualFile)
-   *         If parameter is not ProjectRoot or VirtualFile, returns empty icon "/nodes/emptyNode.png"
-   */
   private static Icon getIconForRoot(Object projectRoot) {
     if (projectRoot instanceof VirtualFile) {
-      final VirtualFile file = (VirtualFile)projectRoot;
+      VirtualFile file = (VirtualFile)projectRoot;
       if (!file.isValid()) {
         return AllIcons.Nodes.PpInvalid;
       }
-      else if (isHttpRoot(file)) {
+      else if (file.getFileSystem() instanceof HttpFileSystem) {
         return PlatformIcons.WEB_ICON;
       }
-      else {
-        return isJarFile(file) ? PlatformIcons.JAR_ICON : PlatformIcons.FILE_ICON;
+      else if (isJarFile(file)) {
+        return PlatformIcons.JAR_ICON;
       }
+      return PlatformIcons.FILE_ICON;
     }
+
     return AllIcons.Nodes.EmptyNode;
   }
 
-  private static boolean isHttpRoot(VirtualFile virtualFileOrProjectRoot) {
-    if (virtualFileOrProjectRoot != null) {
-      return (virtualFileOrProjectRoot.getFileSystem() instanceof HttpFileSystem);
+  protected static class PathCellRenderer extends DefaultListCellRenderer {
+    protected String getItemText(Object value) {
+      return value instanceof VirtualFile ? ((VirtualFile)value).getPresentableUrl() : "UNKNOWN OBJECT";
     }
-    return false;
-  }
 
-  private final class MyCellRenderer extends DefaultListCellRenderer {
-    private String getPresentableString(final Object value) {
-      return ApplicationManager.getApplication().runReadAction(new Computable<String>() {
-        @Override
-        public String compute() {
-          //noinspection HardCodedStringLiteral
-          return (value instanceof VirtualFile) ? ((VirtualFile)value).getPresentableUrl() : "UNKNOWN OBJECT";
-        }
-      });
+    protected Icon getItemIcon(Object value) {
+      return getIconForRoot(value);
     }
 
     @Override
-    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
-      super.getListCellRendererComponent(list, getPresentableString(value), index, isSelected, cellHasFocus);
+    public final Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+      super.getListCellRendererComponent(list, getItemText(value), index, isSelected, cellHasFocus);
+
       if (isSelected) {
         setForeground(UIUtil.getListSelectionForeground());
       }
-      else {
-        if (value instanceof VirtualFile) {
-          VirtualFile file = (VirtualFile)value;
-          if (!file.isValid()) {
-            setForeground(INVALID_COLOR);
-          }
-        }
+      else if (value instanceof VirtualFile && !((VirtualFile)value).isValid()) {
+        setForeground(INVALID_COLOR);
       }
-      setIcon(getIconForRoot(value));
+
+      setIcon(getItemIcon(value));
+
       return this;
     }
   }
index 4ba8b7b03a8d65eb842d68ae8dc4127652c54274..c5c263131f925832881e57419f18af264c5d7dda 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * Copyright 2000-2015 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.
@@ -32,7 +32,6 @@ import com.intellij.openapi.project.DumbModeTask;
 import com.intellij.openapi.project.DumbServiceImpl;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.roots.*;
-import com.intellij.openapi.roots.libraries.Library;
 import com.intellij.openapi.startup.StartupManager;
 import com.intellij.openapi.util.Pair;
 import com.intellij.openapi.vfs.*;
@@ -59,15 +58,17 @@ import java.util.Set;
  */
 public class ProjectRootManagerComponent extends ProjectRootManagerImpl {
   private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.roots.impl.ProjectManagerComponent");
-  private static final boolean ourScheduleCacheUpdateInDumbMode = SystemProperties.getBooleanProperty(
-    "idea.schedule.cache.update.in.dumb.mode", true);
+
+  private static final boolean ourScheduleCacheUpdateInDumbMode =
+    SystemProperties.getBooleanProperty("idea.schedule.cache.update.in.dumb.mode", true);
+
   private boolean myPointerChangesDetected = false;
   private int myInsideRefresh = 0;
   private final BatchUpdateListener myHandler;
   private final MessageBusConnection myConnection;
 
-  protected final List<CacheUpdater> myRootsChangeUpdaters = new ArrayList<CacheUpdater>();
-  protected final List<CacheUpdater> myRefreshCacheUpdaters = new ArrayList<CacheUpdater>();
+  @SuppressWarnings("deprecation") protected final List<CacheUpdater> myRootsChangeUpdaters = new ArrayList<CacheUpdater>();
+  @SuppressWarnings("deprecation") protected final List<CacheUpdater> myRefreshCacheUpdaters = new ArrayList<CacheUpdater>();
 
   private Set<LocalFileSystem.WatchRequest> myRootsToWatch = new THashSet<LocalFileSystem.WatchRequest>();
   private final boolean myDoLogCachesUpdate;
@@ -120,19 +121,23 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl {
     myDoLogCachesUpdate = ApplicationManager.getApplication().isInternal() && !ApplicationManager.getApplication().isUnitTestMode();
   }
 
+  @SuppressWarnings({"deprecation", "unused"})
   public void registerRootsChangeUpdater(CacheUpdater updater) {
     myRootsChangeUpdaters.add(updater);
   }
 
+  @SuppressWarnings({"deprecation", "unused"})
   public void unregisterRootsChangeUpdater(CacheUpdater updater) {
     boolean removed = myRootsChangeUpdaters.remove(updater);
     LOG.assertTrue(removed);
   }
 
+  @SuppressWarnings({"deprecation", "unused"})
   public void registerRefreshUpdater(CacheUpdater updater) {
     myRefreshCacheUpdaters.add(updater);
   }
 
+  @SuppressWarnings({"deprecation", "unused"})
   public void unregisterRefreshUpdater(CacheUpdater updater) {
     boolean removed = myRefreshCacheUpdaters.remove(updater);
     LOG.assertTrue(removed);
@@ -273,27 +278,22 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl {
 
     final Module[] modules = ModuleManager.getInstance(myProject).getModules();
     for (Module module : modules) {
+      flat.add(module.getModuleFilePath());
+
       final ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
 
       addRootsToTrack(moduleRootManager.getContentRootUrls(), recursive, flat);
+
       if (includeSourceRoots) {
         addRootsToTrack(moduleRootManager.getSourceRootUrls(), recursive, flat);
       }
-      flat.add(module.getModuleFilePath());
 
       final OrderEntry[] orderEntries = moduleRootManager.getOrderEntries();
       for (OrderEntry entry : orderEntries) {
-        if (entry instanceof LibraryOrderEntry) {
-          final Library library = ((LibraryOrderEntry)entry).getLibrary();
-          if (library != null) {
-            for (OrderRootType orderRootType : OrderRootType.getAllTypes()) {
-              addRootsToTrack(library.getUrls(orderRootType), recursive, flat);
-            }
-          }
-        }
-        else if (entry instanceof JdkOrderEntry) {
+        if (entry instanceof LibraryOrSdkOrderEntry) {
+          final LibraryOrSdkOrderEntry libSdkEntry = (LibraryOrSdkOrderEntry)entry;
           for (OrderRootType orderRootType : OrderRootType.getAllTypes()) {
-            addRootsToTrack(((JdkOrderEntry)entry).getRootUrls(orderRootType), recursive, flat);
+            addRootsToTrack(libSdkEntry.getRootUrls(orderRootType), recursive, flat);
           }
         }
       }
@@ -302,6 +302,20 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl {
     return Pair.create(recursive, flat);
   }
 
+  private static void addRootsToTrack(final String[] urls, final Collection<String> recursive, final Collection<String> flat) {
+    for (String url : urls) {
+      if (url != null) {
+        final String protocol = VirtualFileManager.extractProtocol(url);
+        if (protocol == null || LocalFileSystem.PROTOCOL.equals(protocol)) {
+          recursive.add(extractLocalPath(url));
+        }
+        else if (JarFileSystem.PROTOCOL.equals(protocol)) {
+          flat.add(extractLocalPath(url));
+        }
+      }
+    }
+  }
+
   @Override
   protected void doSynchronizeRoots() {
     if (!myStartupActivityPerformed) return;
@@ -315,22 +329,9 @@ public class ProjectRootManagerComponent extends ProjectRootManagerImpl {
 
     if (ourScheduleCacheUpdateInDumbMode) {
       dumbService.queueCacheUpdateInDumbMode(myRootsChangeUpdaters);
-    } else {
-      dumbService.queueCacheUpdate(myRootsChangeUpdaters);
     }
-  }
-
-  private static void addRootsToTrack(final String[] urls, final Collection<String> recursive, final Collection<String> flat) {
-    for (String url : urls) {
-      if (url != null) {
-        final String protocol = VirtualFileManager.extractProtocol(url);
-        if (protocol == null || LocalFileSystem.PROTOCOL.equals(protocol)) {
-          recursive.add(extractLocalPath(url));
-        }
-        else if (JarFileSystem.PROTOCOL.equals(protocol)) {
-          flat.add(extractLocalPath(url));
-        }
-      }
+    else {
+      dumbService.queueCacheUpdate(myRootsChangeUpdaters);
     }
   }
 
index 427786101d128498b928718fc78cd6452f0bd436..0cb60f76bcd75f1579aacd3cc25ee28c6c8f3b47 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * Copyright 2000-2015 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.
@@ -41,7 +41,9 @@ public abstract class ArchiveFileSystem extends NewVirtualFileSystem {
    * or null if the file does not host this file system.
    */
   @Nullable
-  public abstract VirtualFile getRootByLocal(@NotNull VirtualFile file);
+  public VirtualFile getRootByLocal(@NotNull VirtualFile file) {
+    return findFileByPath(composeRootPath(file.getPath()));
+  }
 
   /**
    * Returns a root entry of an archive which hosts a given entry file
@@ -73,8 +75,11 @@ public abstract class ArchiveFileSystem extends NewVirtualFileSystem {
   @NotNull
   protected abstract String extractLocalPath(@NotNull String rootPath);
 
+  /**
+   * A reverse to {@link #extractLocalPath(String)} - i.e. dresses a local file path to make it a suitable root path for this filesystem.
+   */
   @NotNull
-  protected abstract String convertLocalToRootPath(@NotNull String localPath);
+  protected abstract String composeRootPath(@NotNull String localPath);
 
   @NotNull
   protected abstract ArchiveHandler getHandler(@NotNull VirtualFile entryFile);
index 7012dd83d47678e6cae342373083720c69b40fe8..72e2737eba25167319c4d81f35a9da283976e7f7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * Copyright 2000-2015 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.
@@ -50,8 +50,7 @@ import java.util.zip.GZIPInputStream;
  * }</pre>
  */
 public final class HttpRequests {
-  private HttpRequests() {
-  }
+  private HttpRequests() { }
 
   public interface Request {
     @NotNull
index 11ba63776be4384d89df50a05ce0071f5b817401..277489dd5aadfe878def5bd358ca8d8c3316fc57 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * Copyright 2000-2015 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.
@@ -105,27 +105,21 @@ public class JarFileSystemImpl extends JarFileSystem {
 
   @NotNull
   @Override
-  protected String convertLocalToRootPath(@NotNull String localPath) {
+  protected String composeRootPath(@NotNull String localPath) {
     return localPath + JAR_SEPARATOR;
   }
 
   @NotNull
   @Override
   protected JarHandler getHandler(@NotNull VirtualFile entryFile) {
-    return VfsImplUtil.getHandler(entryFile, this, new Function<String, JarHandler>() {
+    return VfsImplUtil.getHandler(this, entryFile, new Function<String, JarHandler>() {
       @Override
-      public JarHandler fun(String rootPath) {
-        return new JarHandler(extractLocalPath(rootPath));
+      public JarHandler fun(String localPath) {
+        return new JarHandler(localPath);
       }
     });
   }
 
-  @Nullable
-  @Override
-  public VirtualFile getRootByLocal(@NotNull VirtualFile file) {
-    return findFileByPath(convertLocalToRootPath(file.getPath()));
-  }
-
   @Override
   public VirtualFile findFileByPath(@NotNull String path) {
     return VfsImplUtil.findFileByPath(this, path);
index b8eb6c5f06e2f2a3779679b47e0421607f47c672..132d61496687afb8c51cdb881fe90af2a9a1a374 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * Copyright 2000-2015 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.
@@ -53,11 +53,11 @@ public final class LocalFileSystemImpl extends LocalFileSystemBase implements Ap
   private final FileWatcher myWatcher;
 
   private static class WatchRequestImpl implements WatchRequest {
-    private final boolean myToWatchRecursively;
-    private String myFSRootPath;
+    private final String myFSRootPath;
+    private final boolean myWatchRecursively;
     private boolean myDominated;
 
-    public WatchRequestImpl(String rootPath, boolean toWatchRecursively) throws FileNotFoundException {
+    public WatchRequestImpl(String rootPath, boolean watchRecursively) throws FileNotFoundException {
       int index = rootPath.indexOf(JarFileSystem.JAR_SEPARATOR);
       if (index >= 0) rootPath = rootPath.substring(0, index);
 
@@ -73,7 +73,7 @@ public final class LocalFileSystemImpl extends LocalFileSystemBase implements Ap
       }
 
       myFSRootPath = rootFile.getAbsolutePath();
-      myToWatchRecursively = toWatchRecursively;
+      myWatchRecursively = watchRecursively;
     }
 
     @Override
@@ -84,7 +84,7 @@ public final class LocalFileSystemImpl extends LocalFileSystemBase implements Ap
 
     @Override
     public boolean isToWatchRecursively() {
-      return myToWatchRecursively;
+      return myWatchRecursively;
     }
 
     @Override
@@ -112,8 +112,7 @@ public final class LocalFileSystemImpl extends LocalFileSystemBase implements Ap
   }
 
   @Override
-  public void initComponent() {
-  }
+  public void initComponent() { }
 
   @Override
   public void disposeComponent() {
index ec4e2feea5d0c62e0c833bf61657fda85315f6d1..a46a221bbe58e108b1f7a07faa447da3a1d05e15 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * Copyright 2000-2015 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.
@@ -15,6 +15,7 @@
  */
 package com.intellij.openapi.vfs.newvfs;
 
+import com.intellij.openapi.application.Application;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.application.ModalityState;
 import com.intellij.openapi.diagnostic.Logger;
@@ -22,10 +23,7 @@ import com.intellij.openapi.util.Pair;
 import com.intellij.openapi.util.io.FileUtil;
 import com.intellij.openapi.util.io.ZipFileCache;
 import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.openapi.vfs.LocalFileSystem;
-import com.intellij.openapi.vfs.VFileProperty;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.vfs.VirtualFileManager;
+import com.intellij.openapi.vfs.*;
 import com.intellij.openapi.vfs.impl.ArchiveHandler;
 import com.intellij.openapi.vfs.newvfs.events.VFileCreateEvent;
 import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
@@ -34,22 +32,26 @@ import com.intellij.openapi.vfs.newvfs.events.VFilePropertyChangeEvent;
 import com.intellij.util.Function;
 import com.intellij.util.Processor;
 import com.intellij.util.containers.ContainerUtil;
-import com.intellij.util.messages.MessageBus;
-import gnu.trove.THashSet;
 import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.io.File;
-import java.util.*;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import static com.intellij.util.containers.ContainerUtil.newTroveMap;
+
 public class VfsImplUtil {
   private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vfs.newvfs.VfsImplUtil");
 
   private static final String FILE_SEPARATORS = "/" + File.separator;
 
-  private VfsImplUtil() { }
+  private VfsImplUtil() {
+  }
 
   @Nullable
   public static NewVirtualFile findFileByPath(@NotNull NewVirtualFileSystem vfs, @NotNull @NonNls String path) {
@@ -176,34 +178,40 @@ public class VfsImplUtil {
 
   private static final AtomicBoolean ourSubscribed = new AtomicBoolean(false);
   private static final Object ourLock = new Object();
-  private static final Map<String, Pair<ArchiveFileSystem, ArchiveHandler>> ourHandlers = ContainerUtil.newTroveMap(FileUtil.PATH_HASHING_STRATEGY);
-  private static final Map<String, Set<String>> ourDominatorsMap = ContainerUtil.newTroveMap(FileUtil.PATH_HASHING_STRATEGY);
+  private static final Map<String, Pair<ArchiveFileSystem, ArchiveHandler>> ourHandlers = newTroveMap(FileUtil.PATH_HASHING_STRATEGY);
+  private static final Map<String, Set<String>> ourDominatorsMap = newTroveMap(FileUtil.PATH_HASHING_STRATEGY);
 
   @NotNull
-  public static <T extends ArchiveHandler> T getHandler(@NotNull VirtualFile entryFile,
-                                                        @NotNull ArchiveFileSystem vfs,
+  public static <T extends ArchiveHandler> T getHandler(@NotNull ArchiveFileSystem vfs,
+                                                        @NotNull VirtualFile entryFile,
+                                                        @NotNull Function<String, T> producer) {
+    String localPath = vfs.extractLocalPath(vfs.extractRootPath(entryFile.getPath()));
+    return getHandler(vfs, localPath, producer);
+  }
+
+  @NotNull
+  public static <T extends ArchiveHandler> T getHandler(@NotNull ArchiveFileSystem vfs,
+                                                        @NotNull String localPath,
                                                         @NotNull Function<String, T> producer) {
     checkSubscription();
 
-    String rootPath = vfs.extractRootPath(entryFile.getPath());
-    rootPath = vfs.extractLocalPath(rootPath);
     ArchiveHandler handler;
     boolean refresh = false;
 
     synchronized (ourLock) {
-      Pair<ArchiveFileSystem, ArchiveHandler> record = ourHandlers.get(rootPath);
+      Pair<ArchiveFileSystem, ArchiveHandler> record = ourHandlers.get(localPath);
       if (record == null) {
-        handler = producer.fun(rootPath);
+        handler = producer.fun(localPath);
         record = Pair.create(vfs, handler);
-        ourHandlers.put(rootPath, record);
+        ourHandlers.put(localPath, record);
 
-        final String finalRootPath = rootPath;
-        forEachDirectoryComponent(rootPath, new Processor<String>() {
+        final String finalRootPath = localPath;
+        forEachDirectoryComponent(localPath, new Processor<String>() {
           @Override
           public boolean process(String containingDirectoryPath) {
             Set<String> handlers = ourDominatorsMap.get(containingDirectoryPath);
             if (handlers == null) {
-              ourDominatorsMap.put(containingDirectoryPath, handlers = new THashSet<String>());
+              ourDominatorsMap.put(containingDirectoryPath, handlers = ContainerUtil.newTroveSet());
             }
             handlers.add(finalRootPath);
             return true;
@@ -230,7 +238,7 @@ public class VfsImplUtil {
 
   private static void forEachDirectoryComponent(String rootPath, Processor<String> processor) {
     int index = rootPath.lastIndexOf('/');
-    while(index > 0) {
+    while (index > 0) {
       String containingDirectoryPath = rootPath.substring(0, index);
       if (!processor.process(containingDirectoryPath)) return;
       index = rootPath.lastIndexOf('/', index - 1);
@@ -240,8 +248,8 @@ public class VfsImplUtil {
   private static void checkSubscription() {
     if (ourSubscribed.getAndSet(true)) return;
 
-    MessageBus bus = ApplicationManager.getApplication().getMessageBus();
-    bus.connect().subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener.Adapter() {
+    Application app = ApplicationManager.getApplication();
+    app.getMessageBus().connect(app).subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener.Adapter() {
       @Override
       public void after(@NotNull List<? extends VFileEvent> events) {
         InvalidationState state = null;
@@ -257,22 +265,25 @@ public class VfsImplUtil {
               continue;
             }
 
-            VirtualFile file = event.getFile();
             String path = event.getPath();
             if (event instanceof VFilePropertyChangeEvent) {
               path = ((VFilePropertyChangeEvent)event).getOldPath();
-            } else if (event instanceof VFileMoveEvent) {
+            }
+            else if (event instanceof VFileMoveEvent) {
               path = ((VFileMoveEvent)event).getOldPath();
             }
+
+            VirtualFile file = event.getFile();
             if (file == null || !file.isDirectory()) {
-              if (state == null) state = new InvalidationState();
-              state.invalidateHandlerForPath(path);
-            else {
+              state = InvalidationState.invalidate(state, path);
+            }
+            else {
               Collection<String> affectedPaths = ourDominatorsMap.get(path);
               if (affectedPaths != null) {
-                affectedPaths = new ArrayList<String>(affectedPaths); // defensive copying, we will modify original during invalidate
-                if (state == null) state = new InvalidationState();
-                for (String affectedPath : affectedPaths) state.invalidateHandlerForPath(affectedPath);
+                affectedPaths = ContainerUtil.newArrayList(affectedPaths);  // defensive copying; original may be updated on invalidation
+                for (String affectedPath : affectedPaths) {
+                  state = InvalidationState.invalidate(state, affectedPath);
+                }
               }
             }
           }
@@ -286,38 +297,39 @@ public class VfsImplUtil {
   private static class InvalidationState {
     private Map<String, VirtualFile> rootsToRefresh;
 
-    boolean invalidateHandlerForPath(final String path) {
+    @Nullable
+    public static InvalidationState invalidate(@Nullable InvalidationState state, final String path) {
       Pair<ArchiveFileSystem, ArchiveHandler> handlerPair = ourHandlers.remove(path);
       if (handlerPair != null) {
         forEachDirectoryComponent(path, new Processor<String>() {
           @Override
           public boolean process(String containingDirectoryPath) {
             Set<String> handlers = ourDominatorsMap.get(containingDirectoryPath);
-            if (handlers != null) {
-              if(handlers.remove(path) && handlers.size() == 0) {
-                ourDominatorsMap.remove(containingDirectoryPath);
-              }
+            if (handlers != null && handlers.remove(path) && handlers.size() == 0) {
+              ourDominatorsMap.remove(containingDirectoryPath);
             }
             return true;
           }
         });
-        registerPathToRefresh(handlerPair, path);
+
+        if (state == null) state = new InvalidationState();
+        state.registerPathToRefresh(path, handlerPair.first);
       }
-      return handlerPair != null;
+
+      return state;
     }
 
-    private void registerPathToRefresh(Pair<ArchiveFileSystem, ArchiveHandler> handlerPair, String path) {
-      String rootPath = handlerPair.first.convertLocalToRootPath(path);
-      NewVirtualFile root = ManagingFS.getInstance().findRoot(rootPath, handlerPair.first);
+    private void registerPathToRefresh(String path, ArchiveFileSystem vfs) {
+      NewVirtualFile root = ManagingFS.getInstance().findRoot(vfs.composeRootPath(path), vfs);
       if (root != null) {
         if (rootsToRefresh == null) rootsToRefresh = ContainerUtil.newHashMap();
         rootsToRefresh.put(path, root);
       }
     }
 
-    void scheduleRefresh() {
+    public void scheduleRefresh() {
       if (rootsToRefresh != null) {
-        for(VirtualFile root:rootsToRefresh.values()) {
+        for (VirtualFile root : rootsToRefresh.values()) {
           ((NewVirtualFile)root).markDirtyRecursively();
         }
         ZipFileCache.reset(rootsToRefresh.keySet());