@Override
 public Object[] getDirectoryCachedValueDependencies(PsiPackage psiPackage) {
   return new Object[] {
     PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT,
     ProjectRootManager.getInstance(psiPackage.getProject())
   };
 }
 @Override
 public boolean value(PsiPackage aPackage) {
   return JavaPsiFacade.getInstance(aPackage.getProject())
           .getNameHelper()
           .isQualifiedName(aPackage.getQualifiedName())
       && Character.isLowerCase(aPackage.getName().charAt(0));
 }
  private Object[] processPackage(final PsiPackage aPackage) {
    final ArrayList<Object> list = new ArrayList<Object>();
    final int startOffset =
        StringUtil.isEmpty(aPackage.getName()) ? 0 : aPackage.getQualifiedName().length() + 1;
    final GlobalSearchScope scope = getScope();
    for (final PsiPackage subPackage : aPackage.getSubPackages(scope)) {
      final String shortName = subPackage.getQualifiedName().substring(startOffset);
      if (JavaPsiFacade.getInstance(subPackage.getProject())
          .getNameHelper()
          .isIdentifier(shortName)) {
        list.add(subPackage);
      }
    }

    final PsiClass[] classes = aPackage.getClasses(scope);
    final Map<CustomizableReferenceProvider.CustomizationKey, Object> options = getOptions();
    if (options != null) {
      final boolean instantiatable =
          JavaClassReferenceProvider.INSTANTIATABLE.getBooleanValue(options);
      final boolean concrete = JavaClassReferenceProvider.CONCRETE.getBooleanValue(options);
      final boolean notInterface =
          JavaClassReferenceProvider.NOT_INTERFACE.getBooleanValue(options);
      final boolean notEnum = JavaClassReferenceProvider.NOT_ENUM.getBooleanValue(options);
      final ClassKind classKind = getClassKind();

      for (PsiClass clazz : classes) {
        if (isClassAccepted(clazz, classKind, instantiatable, concrete, notInterface, notEnum)) {
          list.add(clazz);
        }
      }
    } else {
      ContainerUtil.addAll(list, classes);
    }
    return list.toArray();
  }
  private static PsiDirectory[] suggestMostAppropriateDirectories(PsiPackage psiPackage) {
    final Project project = psiPackage.getProject();
    PsiDirectory[] directories = null;
    final Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
    if (editor != null) {
      final Document document = editor.getDocument();
      final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document);
      if (psiFile != null) {
        final Module module = ModuleUtil.findModuleForPsiElement(psiFile);
        if (module != null) {
          directories =
              psiPackage.getDirectories(GlobalSearchScope.moduleWithDependenciesScope(module));
        } else {
          directories =
              psiPackage.getDirectories(
                  GlobalSearchScope.notScope(GlobalSearchScope.projectScope(project)));
        }
      }
    }

    if (directories == null || directories.length == 0) {
      directories = psiPackage.getDirectories();
    }
    return directories;
  }
  @NotNull
  private Object[] getSubclassVariants(
      @NotNull PsiPackage context, @NotNull String[] extendClasses) {
    HashSet<Object> lookups = new HashSet<Object>();
    GlobalSearchScope packageScope = PackageScope.packageScope(context, true);
    GlobalSearchScope scope = myJavaClassReferenceSet.getProvider().getScope();
    if (scope != null) {
      packageScope = packageScope.intersectWith(scope);
    }
    final GlobalSearchScope allScope = ProjectScope.getAllScope(context.getProject());
    final boolean instantiatable =
        JavaClassReferenceProvider.INSTANTIATABLE.getBooleanValue(getOptions());
    final boolean notInterface =
        JavaClassReferenceProvider.NOT_INTERFACE.getBooleanValue(getOptions());
    final boolean notEnum = JavaClassReferenceProvider.NOT_ENUM.getBooleanValue(getOptions());
    final boolean concrete = JavaClassReferenceProvider.CONCRETE.getBooleanValue(getOptions());

    final ClassKind classKind = getClassKind();

    for (String extendClassName : extendClasses) {
      final PsiClass extendClass =
          JavaPsiFacade.getInstance(context.getProject()).findClass(extendClassName, allScope);
      if (extendClass != null) {
        // add itself
        if (packageScope.contains(extendClass.getContainingFile().getVirtualFile())) {
          if (isClassAccepted(
              extendClass, classKind, instantiatable, concrete, notInterface, notEnum)) {
            ContainerUtil.addIfNotNull(createSubclassLookupValue(context, extendClass), lookups);
          }
        }
        for (final PsiClass clazz : ClassInheritorsSearch.search(extendClass, packageScope, true)) {
          if (isClassAccepted(clazz, classKind, instantiatable, concrete, notInterface, notEnum)) {
            ContainerUtil.addIfNotNull(createSubclassLookupValue(context, clazz), lookups);
          }
        }
      }
    }
    return lookups.toArray();
  }
 @Override
 public void navigate(final PsiPackage psiPackage, final boolean requestFocus) {
   final Project project = psiPackage.getProject();
   ToolWindow window =
       ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.PROJECT_VIEW);
   window.activate(null);
   window
       .getActivation()
       .doWhenDone(
           new Runnable() {
             @Override
             public void run() {
               final ProjectView projectView = ProjectView.getInstance(project);
               PsiDirectory[] directories = suggestMostAppropriateDirectories(psiPackage);
               if (directories.length == 0) return;
               projectView.select(directories[0], directories[0].getVirtualFile(), requestFocus);
             }
           });
 }
  @Override
  public void handleQualifiedNameChange(
      final PsiPackage psiPackage, final String newQualifiedName) {
    ApplicationManager.getApplication().assertWriteAccessAllowed();
    final String oldQualifedName = psiPackage.getQualifiedName();
    final boolean anyChanged = changePackagePrefixes(psiPackage, oldQualifedName, newQualifiedName);
    if (anyChanged) {
      UndoManager.getInstance(psiPackage.getProject())
          .undoableActionPerformed(
              new GlobalUndoableAction() {
                @Override
                public void undo() {
                  changePackagePrefixes(psiPackage, newQualifiedName, oldQualifedName);
                }

                @Override
                public void redo() {
                  changePackagePrefixes(psiPackage, oldQualifedName, newQualifiedName);
                }
              });
    }
  }
  private static boolean changePackagePrefixes(
      PsiPackage psiPackage, final String oldQualifiedName, final String newQualifiedName) {
    final Module[] modules = ModuleManager.getInstance(psiPackage.getProject()).getModules();
    List<ModifiableRootModel> modelsToCommit = new ArrayList<ModifiableRootModel>();
    for (final Module module : modules) {
      boolean anyChange = false;
      final ModifiableRootModel rootModel =
          ModuleRootManager.getInstance(module).getModifiableModel();
      for (final ContentEntry contentEntry : rootModel.getContentEntries()) {
        for (final SourceFolder sourceFolder :
            contentEntry.getSourceFolders(JavaModuleSourceRootTypes.SOURCES)) {
          final String packagePrefix = sourceFolder.getPackagePrefix();
          if (packagePrefix.startsWith(oldQualifiedName)) {
            sourceFolder.setPackagePrefix(
                newQualifiedName + packagePrefix.substring(oldQualifiedName.length()));
            anyChange = true;
          }
        }
      }
      if (anyChange) {
        modelsToCommit.add(rootModel);
      } else {
        rootModel.dispose();
      }
    }

    if (!modelsToCommit.isEmpty()) {
      ModifiableRootModel[] rootModels =
          modelsToCommit.toArray(new ModifiableRootModel[modelsToCommit.size()]);
      if (rootModels.length > 0) {
        ModifiableModelCommitter.multiCommit(
            rootModels, ModuleManager.getInstance(rootModels[0].getProject()).getModifiableModel());
      }
      return true;
    } else {
      return false;
    }
  }
  @Override
  public VirtualFile[] occursInPackagePrefixes(PsiPackage psiPackage) {
    List<VirtualFile> result = new ArrayList<VirtualFile>();
    final Module[] modules = ModuleManager.getInstance(psiPackage.getProject()).getModules();

    for (final Module module : modules) {
      for (final ContentEntry contentEntry :
          ModuleRootManager.getInstance(module).getContentEntries()) {
        final List<SourceFolder> sourceFolders =
            contentEntry.getSourceFolders(JavaModuleSourceRootTypes.SOURCES);
        for (final SourceFolder sourceFolder : sourceFolders) {
          final String packagePrefix = sourceFolder.getPackagePrefix();
          if (packagePrefix.startsWith(psiPackage.getQualifiedName())) {
            final VirtualFile file = sourceFolder.getFile();
            if (file != null) {
              result.add(file);
            }
          }
        }
      }
    }

    return VfsUtil.toVirtualFileArray(result);
  }
 @Override
 public GlobalSearchScope adjustAllScope(
     PsiPackage psiPackage, GlobalSearchScope globalSearchScope) {
   return NonClasspathClassFinder.addNonClasspathScope(psiPackage.getProject(), globalSearchScope);
 }
 @Override
 public boolean packagePrefixExists(PsiPackage psiPackage) {
   return PackagePrefixElementFinder.getInstance(psiPackage.getProject())
       .packagePrefixExists(psiPackage.getQualifiedName());
 }