Merge branch 'master' of git.labs.intellij.net:idea/community

This commit is contained in:
Irina Chernushina
2009-10-26 17:00:50 +03:00
69 changed files with 1681 additions and 1005 deletions
@@ -63,7 +63,7 @@ public class ArtifactsGenerator {
generators.add(initTarget);
initTarget.add(new Property(ArtifactAntGenerationContextImpl.ARTIFACTS_TEMP_DIR_PROPERTY, BuildProperties.propertyRelativePath(BuildProperties.getProjectBaseDirProperty(), "artifactsTemp")));
final Artifact[] artifacts = ArtifactManager.getInstance(myProject).getArtifacts();
final Artifact[] artifacts = ArtifactManager.getInstance(myProject).getSortedArtifacts();
for (Artifact artifact : artifacts) {
if (!myContext.shouldBuildIntoTempDirectory(artifact)) {
generators.add(new CleanArtifactTarget(artifact, myContext));
@@ -1,72 +0,0 @@
/*
* Copyright 2000-2009 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.packaging.impl.elements;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.IconLoader;
import com.intellij.packaging.artifacts.Artifact;
import com.intellij.packaging.elements.ComplexPackagingElementType;
import com.intellij.packaging.elements.CompositePackagingElement;
import com.intellij.packaging.ui.ArtifactEditorContext;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.util.ArrayList;
import java.util.List;
/**
* @author nik
*/
public class ModuleWithDependenciesElementType extends ComplexPackagingElementType<ModuleWithDependenciesPackagingElement> {
public static final ModuleWithDependenciesElementType MODULE_WITH_DEPENDENCIES_TYPE = new ModuleWithDependenciesElementType();
public ModuleWithDependenciesElementType() {
super("module-with-dependencies", "Module With Dependencies");
}
@Override
public String getShowContentActionText() {
return "Module with dependencies";
}
@Override
public Icon getCreateElementIcon() {
return IconLoader.getIcon("/nodes/ModuleOpen.png");
}
@Override
public boolean canCreate(@NotNull ArtifactEditorContext context, @NotNull Artifact artifact) {
return context.getModulesProvider().getModules().length > 0;
}
@NotNull
public List<? extends ModuleWithDependenciesPackagingElement> chooseAndCreate(@NotNull ArtifactEditorContext context,
@NotNull Artifact artifact,
@NotNull CompositePackagingElement<?> parent) {
final List<Module> modules = ModuleOutputElementType.chooseModules(context);
final List<ModuleWithDependenciesPackagingElement> elements = new ArrayList<ModuleWithDependenciesPackagingElement>();
for (Module module : modules) {
elements.add(new ModuleWithDependenciesPackagingElement(module.getName()));
}
return elements;
}
@NotNull
public ModuleWithDependenciesPackagingElement createEmpty(@NotNull Project project) {
return new ModuleWithDependenciesPackagingElement();
}
}
@@ -1,127 +0,0 @@
/*
* Copyright 2000-2009 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.packaging.impl.elements;
import com.intellij.openapi.compiler.CompilerBundle;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.packaging.elements.ComplexPackagingElement;
import com.intellij.packaging.elements.PackagingElement;
import com.intellij.packaging.elements.PackagingElementFactory;
import com.intellij.packaging.elements.PackagingElementResolvingContext;
import com.intellij.packaging.impl.ui.DelegatedPackagingElementPresentation;
import com.intellij.packaging.impl.ui.ModuleElementPresentation;
import com.intellij.packaging.ui.PackagingElementPresentation;
import com.intellij.packaging.ui.PackagingElementWeights;
import com.intellij.packaging.ui.ArtifactEditorContext;
import com.intellij.packaging.artifacts.ArtifactType;
import com.intellij.util.xmlb.annotations.Attribute;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* @author nik
*/
public class ModuleWithDependenciesPackagingElement extends ComplexPackagingElement<ModuleWithDependenciesPackagingElement> {
private String myModuleName;
public ModuleWithDependenciesPackagingElement() {
super(ModuleWithDependenciesElementType.MODULE_WITH_DEPENDENCIES_TYPE);
}
public ModuleWithDependenciesPackagingElement(String moduleName) {
super(ModuleWithDependenciesElementType.MODULE_WITH_DEPENDENCIES_TYPE);
myModuleName = moduleName;
}
public List<? extends PackagingElement<?>> getSubstitution(@NotNull PackagingElementResolvingContext context, @NotNull ArtifactType artifactType) {
final Module module = findModule(context);
List<PackagingElement<?>> elements = new ArrayList<PackagingElement<?>>();
final PackagingElementFactory factory = PackagingElementFactory.getInstance();
if (module != null) {
final ModuleRootModel rootModel = context.getModulesProvider().getRootModel(module);
for (OrderEntry entry : rootModel.getOrderEntries()) {
if (entry instanceof ModuleSourceOrderEntry) {
elements.add(factory.createModuleOutput(myModuleName, context.getProject()));
}
else if (entry instanceof LibraryOrderEntry) {
final Library library = ((LibraryOrderEntry)entry).getLibrary();
if (library != null) {
elements.addAll(factory.createLibraryElements(library));
}
}
else if (entry instanceof ModuleOrderEntry) {
elements.add(new ModuleWithDependenciesPackagingElement(((ModuleOrderEntry)entry).getModuleName()));
}
}
}
final List<PackagingElement<?>> substitution = new ArrayList<PackagingElement<?>>();
for (PackagingElement<?> element : elements) {
final String path = artifactType.getDefaultPathFor(element, context);
if (path != null) {
substitution.add(factory.createParentDirectories(path, element));
}
}
return substitution;
}
public PackagingElementPresentation createPresentation(@NotNull ArtifactEditorContext context) {
return new DelegatedPackagingElementPresentation(new ModuleElementPresentation(myModuleName, findModule(context), context) {
@Override
protected String getNodeText() {
return CompilerBundle.message("node.text.0.with.dependencies", getPresentableName());
}
@Override
public int getWeight() {
return PackagingElementWeights.ARTIFACT - 10;
}
});
}
public boolean isEqualTo(@NotNull PackagingElement<?> element) {
return element instanceof ModuleWithDependenciesPackagingElement && myModuleName != null
&& myModuleName.equals(((ModuleWithDependenciesPackagingElement)element).getModuleName());
}
public ModuleWithDependenciesPackagingElement getState() {
return this;
}
public void loadState(ModuleWithDependenciesPackagingElement state) {
myModuleName = state.getModuleName();
}
@Nullable
public Module findModule(PackagingElementResolvingContext context) {
return context.getModulesProvider().getModule(myModuleName);
}
@Attribute("module-name")
public String getModuleName() {
return myModuleName;
}
public void setModuleName(String moduleName) {
myModuleName = moduleName;
}
}
@@ -64,7 +64,6 @@ public class PackagingElementFactoryImpl extends PackagingElementFactory {
private static final PackagingElementType[] STANDARD_TYPES = {
DIRECTORY_ELEMENT_TYPE, ARCHIVE_ELEMENT_TYPE,
LibraryElementType.LIBRARY_ELEMENT_TYPE, ModuleOutputElementType.MODULE_OUTPUT_ELEMENT_TYPE,
//ModuleWithDependenciesElementType.MODULE_WITH_DEPENDENCIES_TYPE,
ArtifactElementType.ARTIFACT_ELEMENT_TYPE, FILE_COPY_ELEMENT_TYPE, DIRECTORY_COPY_ELEMENT_TYPE
};
@@ -130,7 +130,7 @@ public abstract class ElementWithManifestPropertiesPanel<E extends CompositeElem
private void createManifest() {
FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
descriptor.setTitle("Select Directory for MANIFEST.MF file");
descriptor.setTitle("Select Directory for META-INF/MANIFEST.MF file");
final VirtualFile[] files = FileChooser.chooseFiles(myContext.getProject(), descriptor, ManifestFileUtil.suggestManifestFileDirectory(myElement, myContext, myContext.getArtifactType()));
if (files.length != 1) return;
@@ -60,11 +60,6 @@ public abstract class ArtifactType {
return getDefaultPathFor(sourceItem.getKindOfProducedElements());
}
@Nullable
public String getDefaultPathFor(@NotNull PackagingElement<?> element, @NotNull PackagingElementResolvingContext context) {
return getDefaultPathFor(element.getFilesKind(context));
}
@Nullable
public abstract String getDefaultPathFor(@NotNull PackagingElementOutputKind kind);
@@ -64,6 +64,10 @@ public class ArtifactSourceItem extends PackagingSourceItem {
return myArtifact.getArtifactType() instanceof JarArtifactType ? PackagingElementOutputKind.JAR_FILES : PackagingElementOutputKind.OTHER;
}
public Artifact getArtifact() {
return myArtifact;
}
public int hashCode() {
return myArtifact.hashCode();
}
@@ -13,6 +13,7 @@ import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* @author nik
@@ -25,7 +26,7 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
private Set<ProjectStructureElement> myElementWithNotCalculatedUsages = new HashSet<ProjectStructureElement>();
private MergingUpdateQueue myAnalyzerQueue;
private List<Runnable> myListeners = new ArrayList<Runnable>();
private boolean myStopped;
private final AtomicBoolean myStopped = new AtomicBoolean(false);
public ProjectStructureDaemonAnalyzer(StructureConfigurableContext context) {
Disposer.register(context, this);
@@ -33,7 +34,7 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
}
private void doUpdate(final ProjectStructureElement element, final boolean check, final boolean collectUsages) {
if (myStopped) return;
if (myStopped.get()) return;
if (check) {
doCheck(element);
@@ -47,7 +48,7 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
final ProjectStructureProblemsHolder problemsHolder = new ProjectStructureProblemsHolder();
new ReadAction() {
protected void run(final Result result) {
if (myStopped) return;
if (myStopped.get()) return;
if (LOG.isDebugEnabled()) {
LOG.debug("checking " + element);
@@ -57,7 +58,7 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
}.execute();
invokeLater(new Runnable() {
public void run() {
if (myStopped) return;
if (myStopped.get()) return;
if (LOG.isDebugEnabled()) {
LOG.debug("updating problems for " + element);
@@ -78,7 +79,7 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
private void doCollectUsages(final ProjectStructureElement element) {
final List<ProjectStructureElementUsage> usages = new ReadAction<List<ProjectStructureElementUsage>>() {
protected void run(final Result<List<ProjectStructureElementUsage>> result) {
if (myStopped) return;
if (myStopped.get()) return;
if (LOG.isDebugEnabled()) {
LOG.debug("collecting usages in " + element);
@@ -89,7 +90,7 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
invokeLater(new Runnable() {
public void run() {
if (myStopped) return;
if (myStopped.get()) return;
if (LOG.isDebugEnabled()) {
LOG.debug("updating usages for " + element);
@@ -166,7 +167,7 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
public void stop() {
LOG.debug("analyzer stopped");
myStopped = true;
myStopped.set(true);
myAnalyzerQueue.cancelAllUpdates();
clearCaches();
myAnalyzerQueue.deactivate();
@@ -183,7 +184,7 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
}
public void dispose() {
myStopped = true;
myStopped.set(true);
myAnalyzerQueue.cancelAllUpdates();
}
@@ -211,7 +212,7 @@ public class ProjectStructureDaemonAnalyzer implements Disposable {
myAnalyzerQueue.activate();
myAnalyzerQueue.queue(new Update("reset") {
public void run() {
myStopped = false;
myStopped.set(false);
}
});
}
@@ -55,10 +55,6 @@ public class ConfigFileFactoryImpl extends ConfigFileFactory {
return new ConfigFileContainerImpl(project, metaDataProvider, (ConfigFileInfoSetImpl)configuration);
}
public CustomConfigFileSet createCustomConfigFileSet() {
return new CustomConfigFileSetImpl();
}
private static String getText(final String templateName) throws IOException {
final FileTemplateManager templateManager = FileTemplateManager.getInstance();
final FileTemplate template = templateManager.getJ2eeTemplate(templateName);
@@ -1,99 +0,0 @@
/*
* Copyright 2000-2009 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.util.descriptors.impl;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.util.descriptors.CustomConfigFile;
import com.intellij.util.descriptors.CustomConfigFileSet;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @author nik
*/
public class CustomConfigFileSetImpl implements CustomConfigFileSet {
@NonNls private static final String ELEMENT_NAME = "deploymentDescriptor";
@NonNls private static final String URL_ATTRIBUTE = "url";
@NonNls private static final String OPTION_ELEMENT_NAME = "option";
@NonNls private static final String DEFAULT_DIR_OPTION = "DEFAULT_DIR";
@NonNls private static final String NAME_ATTRIBUTE = "name";
@NonNls private static final String VALUE_ATTRIBUTE = "value";
private final List<CustomConfigFile> myDescriptors = new ArrayList<CustomConfigFile>();
public void add(CustomConfigFile descriptor) {
myDescriptors.add(descriptor);
}
public void remove(CustomConfigFile descriptor) {
myDescriptors.remove(descriptor);
}
public CustomConfigFile[] getConfigFiles() {
return myDescriptors.toArray(new CustomConfigFile[myDescriptors.size()]);
}
public void setConfigFiles(final Collection<CustomConfigFile> descriptors) {
myDescriptors.clear();
myDescriptors.addAll(descriptors);
}
public void readExternal(Element element) {
doReadExternal(element, new ArrayList<Element>());
}
public void doReadExternal(Element element, List<Element> descriptorElements) {
myDescriptors.clear();
List<Element> descriptors = element.getChildren(ELEMENT_NAME);
for (Element descriptor : descriptors) {
String url = descriptor.getAttributeValue(URL_ATTRIBUTE);
String directory = getDefaultDirOption(descriptor);
if (directory != null) {
myDescriptors.add(new CustomConfigFile(url, directory));
descriptorElements.add(descriptor);
}
}
}
@Nullable
private static String getDefaultDirOption(final Element descriptor) {
List<Element> options = descriptor.getChildren(OPTION_ELEMENT_NAME);
for (Element option : options) {
if (DEFAULT_DIR_OPTION.equals(option.getAttributeValue(NAME_ATTRIBUTE))) {
return option.getAttributeValue(VALUE_ATTRIBUTE);
}
}
return null;
}
public void writeExternal(Element element) throws WriteExternalException {
for (CustomConfigFile descriptor : myDescriptors) {
final Element child = new Element(ELEMENT_NAME);
child.setAttribute(URL_ATTRIBUTE, descriptor.getUrl());
final Element option = new Element(OPTION_ELEMENT_NAME);
option.setAttribute(NAME_ATTRIBUTE, DEFAULT_DIR_OPTION);
option.setAttribute(VALUE_ATTRIBUTE, descriptor.getOutputDirectoryPath());
child.addContent(option);
element.addContent(child);
}
}
}
@@ -66,8 +66,7 @@ public abstract class CreateTemplateInPackageAction<T extends PsiElement> extend
}
});
if (createdElement != null) {
final PsiElement navigationElement = getNavigationElement(createdElement);
view.selectElement(navigationElement == null ? createdElement : navigationElement);
view.selectElement(createdElement);
}
}
@@ -40,8 +40,6 @@ public abstract class ConfigFileFactory {
public abstract ConfigFileMetaDataRegistry createMetaDataRegistry();
public abstract CustomConfigFileSet createCustomConfigFileSet();
@Nullable
public abstract VirtualFile createFile(@Nullable Project project, String url, ConfigFileVersion version, final boolean forceNew);
@@ -1,37 +0,0 @@
/*
* Copyright 2000-2009 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.util.descriptors;
import com.intellij.openapi.util.JDOMExternalizable;
import java.util.Collection;
/**
* @author nik
*
* todo[nik] delete
*/
public interface CustomConfigFileSet extends JDOMExternalizable {
void add(CustomConfigFile descriptor);
void remove(CustomConfigFile descriptor);
CustomConfigFile[] getConfigFiles();
void setConfigFiles(Collection<CustomConfigFile> descriptors);
}
@@ -19,8 +19,10 @@ import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementPresentation;
import com.intellij.lang.Language;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.KeyedExtensionCollector;
import com.intellij.openapi.util.Pair;
import com.intellij.patterns.ElementPattern;
@@ -213,8 +215,12 @@ public abstract class CompletionContributor extends AbstractCompletionContributo
return KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction(actionId));
}
public static List<CompletionContributor> forParameters(CompletionParameters parameters) {
return forLanguage(PsiUtilBase.getLanguageAtOffset(parameters.getPosition().getContainingFile(), parameters.getOffset()));
public static List<CompletionContributor> forParameters(final CompletionParameters parameters) {
return ApplicationManager.getApplication().runReadAction(new Computable<List<CompletionContributor>>() {
public List<CompletionContributor> compute() {
return forLanguage(PsiUtilBase.getLanguageAtOffset(parameters.getPosition().getContainingFile(), parameters.getOffset()));
}
});
}
public static List<CompletionContributor> forLanguage(Language language) {
@@ -1194,16 +1194,22 @@ public final class ProjectViewImpl extends ProjectView implements PersistentStat
private final class MyIdeView implements IdeView {
public void selectElement(PsiElement element) {
selectPsiElement(element, true);
selectPsiElement(element, false);
boolean requestFocus = true;
if (element != null) {
final boolean isDirectory = element instanceof PsiDirectory;
if (!isDirectory) {
Editor editor = EditorHelper.openInEditor(element);
if (editor != null) {
ToolWindowManager.getInstance(myProject).activateEditorComponent();
requestFocus = false;
}
}
}
if (requestFocus) {
selectPsiElement(element, true);
}
}
public PsiDirectory[] getDirectories() {
@@ -266,7 +266,6 @@ public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IM
@Override
public void reinitComponents(Set<String> componentNames, boolean reloadData) {
LOG.info("[STORAGE] Module: " + myModule.getName());
super.reinitComponents(componentNames, reloadData);
}
@@ -829,7 +829,12 @@ public class AbstractTreeUi {
boolean notRequiredToUpdateChildren = !forcedNow && !wasExpanded;
if (notRequiredToUpdateChildren && forceUpdate && !wasExpanded) {
notRequiredToUpdateChildren = getBuilder().isAlwaysShowPlus(descriptor);
boolean alwaysPlus = getBuilder().isAlwaysShowPlus(descriptor);
if (alwaysPlus && wasLeaf) {
notRequiredToUpdateChildren = false;
} else {
notRequiredToUpdateChildren = alwaysPlus;
}
}
final Ref<LoadedChildren> preloaded = new Ref<LoadedChildren>(loadedChildren);
@@ -2956,7 +2961,9 @@ public class AbstractTreeUi {
if (myTree.isExpanded(getPathFor(toExpand)) && !myUnbuiltNodes.contains(toExpand)) {
processNodeActionsIfReady(toExpand);
if (!areChildrenToBeUpdated(toExpand)) {
processNodeActionsIfReady(toExpand);
}
}
else {
if (!myUnbuiltNodes.contains(toExpand)) {
@@ -2968,6 +2975,9 @@ public class AbstractTreeUi {
}
}
private boolean areChildrenToBeUpdated(DefaultMutableTreeNode node) {
return getUpdater().isEnqueuedToUpdate(node) || isUpdatingParent(node);
}
private String asString(DefaultMutableTreeNode node) {
if (node == null) return null;
@@ -316,4 +316,13 @@ public class AbstractTreeUpdater implements Disposable, Activatable {
public void flush() {
myUpdateQueue.sendFlush();
}
public boolean isEnqueuedToUpdate(DefaultMutableTreeNode node) {
Iterator<TreeUpdatePass> nodes = myNodeQueue.iterator();
while (nodes.hasNext()) {
TreeUpdatePass each = nodes.next();
if (each.willUpdate(node)) return true;
}
return false;
}
}
@@ -79,4 +79,9 @@ public class TreeUpdatePass {
public String toString() {
return "TreUpdatePass node=" + myNode + " stamp=" + myUpdateStamp + " expired=" + myExpired + " currentNode=" + myCurrentNode + " allocation=" + myAllocation;
}
public boolean willUpdate(@NotNull DefaultMutableTreeNode node) {
@NotNull DefaultMutableTreeNode currentNode = myCurrentNode != null ? myCurrentNode : myNode;
return node.isNodeAncestor(currentNode);
}
}
@@ -497,7 +497,6 @@ abstract class ComponentStoreImpl implements IComponentStore {
for (String componentName : componentNames) {
final PersistentStateComponent component = (PersistentStateComponent)myComponents.get(componentName);
if (component != null) {
LOG.info("[STORAGE] Reinit component '" + componentName + "'");
initPersistentComponent(component, reloadData);
}
}
@@ -93,7 +93,6 @@ public class FileBasedStorage extends XmlElementStorage {
final Listener listener = messageBus.syncPublisher(STORAGE_TOPIC);
virtualFileTracker.addTracker(fileUrl, new VirtualFileAdapter() {
public void contentsChanged(final VirtualFileEvent event) {
LOG.info("[STORAGE] Changed: " + myFilePath);
listener.storageFileChanged(event, FileBasedStorage.this);
}
}, false, this);
@@ -624,14 +624,11 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
final Set<String> componentNames;
try {
componentNames = saveSession.analyzeExternalChanges(changedFiles);
LOG.info("[STORAGE] Changes affects: " + (componentNames == null ? "[NONE]" :
StringUtil.join(componentNames.toArray(new String[componentNames.size()]), ", ")));
if (componentNames == null) return false;
// TODO[mike]: This is a hack to prevent NPE (assert != null) in StateStorageManagerImpl.reload, storage is null for...
for (Pair<VirtualFile, StateStorage> pair : changedFiles) {
if (pair.second == null) {
LOG.info("[STORAGE] Soft reload is not possible: no state for:" + pair.first.getName());
return false;
}
}
@@ -641,7 +638,6 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
}
if (!isReloadPossible(componentNames)) {
LOG.info("[STORAGE] Soft reload is not possible for some components :(");
return false;
}
}
@@ -23,6 +23,7 @@ import com.intellij.openapi.options.StreamProvider;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.MultiMap;
@@ -267,6 +268,11 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
return null;
}
final String extension = FileUtil.getExtension(new File(expandedFile).getName());
if (extension.length() == 0) {
throw new IllegalArgumentException("Extension is missing for storage file: " + expandedFile);
}
return createFileStateStorage(fileSpec, expandedFile, myRootTagName, myPicoContainer);
}
@@ -116,9 +116,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
connection.subscribe(StateStorage.STORAGE_TOPIC, new StateStorage.Listener() {
public void storageFileChanged(final VirtualFileEvent event, @NotNull final StateStorage storage) {
VirtualFile file = event.getFile();
LOG.info("[STORAGE] Check if application reload is required for: " + file.getPath());
if (!file.isDirectory() && !(event.getRequestor() instanceof StateStorage.SaveSession)) {
LOG.info("[STORAGE] Scheduling application reload triggered by change in: " + file.getPath());
saveChangedProjectFile(file, null, storage);
}
}
@@ -133,9 +131,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
connection.subscribe(StateStorage.STORAGE_TOPIC, new StateStorage.Listener() {
public void storageFileChanged(final VirtualFileEvent event, @NotNull final StateStorage storage) {
VirtualFile file = event.getFile();
LOG.info("[STORAGE] Check if project reload is required for: " + file.getPath());
if (!file.isDirectory() && !(event.getRequestor() instanceof StateStorage.SaveSession)) {
LOG.info("[STORAGE] Scheduling project reload triggered by change in: " + file.getPath());
saveChangedProjectFile(file, project, storage);
}
}
@@ -575,7 +571,6 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
}
private void askToReloadProjectIfConfigFilesChangedExternally() {
LOG.info("[STORAGE] trying to reload project while myReloadBlockCount = " + myReloadBlockCount);
if (myReloadBlockCount.get() == 0) {
Set<Project> projects;
@@ -584,8 +579,6 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
projects = new HashSet<Project>(myChangedProjectFiles.keySet());
}
LOG.info("[STORAGE] iterate over opened project & reload");
List<Project> projectsToReload = new ArrayList<Project>();
for (Project project : projects) {
@@ -661,8 +654,6 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
if (project.isDisposed()) return false;
final HashSet<Pair<VirtualFile, StateStorage>> causes = new HashSet<Pair<VirtualFile, StateStorage>>();
LOG.info("[STORAGE] Should reload project now");
synchronized (myChangedProjectFiles) {
final List<Pair<VirtualFile, StateStorage>> changes = myChangedProjectFiles.remove(project);
if (changes != null) {
@@ -677,7 +668,6 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
try {
LOG.info("[STORAGE] Checking if we could reinit components w/o project reload...");
reloadOk[0] = ((ProjectEx)project).getStateStore().reload(causes);
}
catch (StateStorage.StateStorageException e) {
@@ -692,8 +682,6 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
});
if (reloadOk[0]) return false;
LOG.info("[STORAGE] Unable to reinit components, scheduling full project reload...");
String message;
if (causes.size() == 1) {
message = ProjectBundle.message("project.reload.external.change.single", causes.iterator().next().first.getPresentableUrl());
@@ -730,13 +718,9 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
}
private void scheduleReloadApplicationAndProject() {
LOG.info("[STORAGE] Scheduling reload with myReloadBlockCount = " + myReloadBlockCount);
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
LOG.info("[STORAGE] trying reloading application and should reload project");
if (!tryToReloadApplication()) return;
LOG.info("[STORAGE] reloading project");
askToReloadProjectIfConfigFilesChangedExternally();
}
@@ -21,7 +21,6 @@ import com.intellij.openapi.components.ApplicationComponent;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.impl.win32.Win32Kernel;
@@ -125,9 +124,7 @@ public final class LocalFileSystemImpl extends LocalFileSystemBase implements Ap
}
public void disposeComponent() {
if (SystemInfo.isWindows && Registry.is("filesystem.useNative")) {
Win32Kernel.release();
}
Win32Kernel.release();
}
@TestOnly
@@ -34,31 +34,47 @@ import java.util.Map;
*/
public class Win32Kernel {
private static Kernel32 myKernel = (Kernel32)Native.loadLibrary("kernel32", Kernel32.class, new HashMap<Object, Object>() {
{
put(Library.OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
put(Library.OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
}});
private static Kernel32 ourKernel;
private static final int MAX_PATH = 0x00000104;
public static final int FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
public static final int FILE_ATTRIBUTE_READONLY = 0x0001;
private synchronized static Kernel32 getKernel() {
if (ourKernel == null) {
ourKernel = (Kernel32)Native.loadLibrary("kernel32", Kernel32.class, new HashMap<Object, Object>() {
{
put(Library.OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
put(Library.OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
}});
WIN32_FIND_DATA.INSTANCE = new WIN32_FIND_DATA();
BY_HANDLE_FILE_INFORMATION.INSTANCE = new BY_HANDLE_FILE_INFORMATION();
}
return ourKernel;
}
private static class FileInfo {
private FileInfo(WIN32_FIND_DATA data) {
this.dwFileAttributes = data.dwFileAttributes;
this.ftLastWriteTime = data.ftLastWriteTime.toLong();
}
private FileInfo(BY_HANDLE_FILE_INFORMATION information) {
this.dwFileAttributes = information.dwFileAttributes;
this.ftLastWriteTime = information.ftLastWriteTime.toLong();
}
int dwFileAttributes;
long ftLastWriteTime;
}
private static W32API.HANDLE INVALID_HANDLE_VALUE = new W32API.HANDLE(Pointer.createConstant(0xFFFFFFFFl));
private static WIN32_FIND_DATA DATA = new WIN32_FIND_DATA();
public static void release() {
DATA = null;
if (ourKernel != null) {
WIN32_FIND_DATA.INSTANCE = null;
BY_HANDLE_FILE_INFORMATION.INSTANCE = null;
}
}
private Map<String, FileInfo> myCache = new HashMap<String, FileInfo>();
@@ -68,22 +84,27 @@ public class Win32Kernel {
myCache.clear();
ArrayList<String> list = new ArrayList<String>();
W32API.HANDLE hFind = myKernel.FindFirstFile(absolutePath.replace('/', '\\') + "\\*", DATA);
W32API.HANDLE hFind = getKernel().FindFirstFile(absolutePath.replace('/', '\\') + "\\*", WIN32_FIND_DATA.INSTANCE);
if (hFind.equals(INVALID_HANDLE_VALUE)) return new String[0];
do {
String name = toString(DATA.cFileName);
if (name.equals(".") || name.equals("..")) {
String name = Native.toString(WIN32_FIND_DATA.INSTANCE.cFileName);
if (name.equals(".")) {
myCache.put(absolutePath, new FileInfo(WIN32_FIND_DATA.INSTANCE));
continue;
}
myCache.put(absolutePath + "/" + name, new FileInfo(DATA));
else if (name.equals("..")) {
continue;
}
myCache.put(absolutePath + "/" + name, new FileInfo(WIN32_FIND_DATA.INSTANCE));
list.add(name);
}
while (myKernel.FindNextFile(hFind, DATA));
myKernel.FindClose(hFind);
while (getKernel().FindNextFile(hFind, WIN32_FIND_DATA.INSTANCE));
getKernel().FindClose(hFind);
return list.toArray(new String[list.size()]);
}
public boolean exists(String path) {
myCache.clear();
try {
getData(path);
return true;
@@ -110,42 +131,38 @@ public class Win32Kernel {
FileInfo data = myCache.get(path);
if (data == null) {
myCache.clear();
W32API.HANDLE hFind = myKernel.FindFirstFile(path.replace('/', '\\'), DATA);
if (hFind.equals(INVALID_HANDLE_VALUE)) throw new FileNotFoundException(path);
data = new FileInfo(DATA);
myKernel.FindClose(hFind);
if (!getKernel().GetFileAttributesEx(path.replace('/', '\\'), 0, BY_HANDLE_FILE_INFORMATION.INSTANCE)) {
throw new FileNotFoundException(path);
}
data = new FileInfo(BY_HANDLE_FILE_INFORMATION.INSTANCE);
myCache.put(path, data);
}
return data;
}
private static String toString(char[] array) {
for (int i = 0; i < array.length; i++) {
if (array[i] == 0) return new String(array, 0, i);
}
return new String(array);
}
public interface Kernel32 extends StdCallLibrary {
W32API.HANDLE FindFirstFile(String lpFileName, WIN32_FIND_DATA lpFindFileData);
boolean GetFileAttributesEx(String lpFileName, int level, BY_HANDLE_FILE_INFORMATION lpFileInformation);
boolean FindNextFile(W32API.HANDLE hFindFile, WIN32_FIND_DATA lpFindFileData);
boolean FindClose(W32API.HANDLE hFindFile);
}
public static class FILETIME extends Structure implements Structure.ByValue {
public int dwLowDateTime;
public int dwHighDateTime;
private static long l(int i) {
if (i >= 0) {
return i;
} else {
return ((long) i & 0x7FFFFFFFl) + 0x80000000l;
}
if (i >= 0) {
return i;
}
else {
return ((long)i & 0x7FFFFFFFl) + 0x80000000l;
}
}
public long toLong() {
@@ -156,6 +173,8 @@ public class Win32Kernel {
@SuppressWarnings({"UnusedDeclaration"})
public static class WIN32_FIND_DATA extends Structure {
public static WIN32_FIND_DATA INSTANCE;
public int dwFileAttributes;
public FILETIME ftCreationTime;
@@ -169,11 +188,24 @@ public class Win32Kernel {
public int nFileSizeLow;
public int dwReserved0;
public int dwReserved1;
public char[] cFileName = new char[MAX_PATH];
public char[] cAlternateFileName = new char[14];
}
@SuppressWarnings({"UnusedDeclaration"})
public static class BY_HANDLE_FILE_INFORMATION extends Structure {
public static BY_HANDLE_FILE_INFORMATION INSTANCE;
public int dwFileAttributes;
public FILETIME ftCreationTime;
public FILETIME ftLastAccessTime;
public FILETIME ftLastWriteTime;
public int nFileSizeHigh;
public int nFileSizeLow;
}
}
@@ -33,19 +33,33 @@ public class Win32LocalFileSystem extends LocalFileSystemBase {
@Override
public String[] list(VirtualFile file) {
try {
return myKernel.list(file.getPath());
String[] strings = myKernel.list(file.getPath());
//assert Arrays.asList(strings).equals(Arrays.asList(super.list(file)));
return strings;
}
catch (Exception e) {
// assert false;
return super.list(file);
}
}
@Override
public boolean exists(VirtualFile fileOrDirectory) {
if (fileOrDirectory.getParent() == null) return true;
boolean b = myKernel.exists(fileOrDirectory.getPath());
//assert b == super.exists(fileOrDirectory);
return b;
}
@Override
public boolean isDirectory(VirtualFile file) {
try {
return myKernel.isDirectory(file.getPath());
boolean b = myKernel.isDirectory(file.getPath());
//assert b == super.isDirectory(file);
return b;
}
catch (FileNotFoundException e) {
// assert false;
return super.isDirectory(file);
}
}
@@ -53,9 +67,12 @@ public class Win32LocalFileSystem extends LocalFileSystemBase {
@Override
public boolean isWritable(VirtualFile file) {
try {
return myKernel.isWritable(file.getPath());
boolean b = myKernel.isWritable(file.getPath());
//assert b == super.isWritable(file);
return b;
}
catch (FileNotFoundException e) {
// assert false: file;
return super.isWritable(file);
}
}
@@ -63,18 +80,16 @@ public class Win32LocalFileSystem extends LocalFileSystemBase {
@Override
public long getTimeStamp(VirtualFile file) {
try {
return myKernel.getTimeStamp(file.getPath());
long timeStamp = myKernel.getTimeStamp(file.getPath());
//assert timeStamp == super.getTimeStamp(file);
return timeStamp;
}
catch (FileNotFoundException e) {
// assert false;
return super.getTimeStamp(file);
}
}
@Override
public boolean exists(VirtualFile fileOrDirectory) {
return myKernel.exists(fileOrDirectory.getPath());
}
@Override
public WatchRequest addRootToWatch(@NotNull String rootPath, boolean toWatchRecursively) {
throw new UnsupportedOperationException();
@@ -19,6 +19,7 @@
*/
package com.intellij.openapi.vfs.newvfs.persistent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vfs.LocalFileSystem;
@@ -58,7 +59,7 @@ public class RefreshWorker {
}
else {
if (delegate.getProtocol().equals(LocalFileSystem.PROTOCOL) && SystemInfo.isWindows && root.isDirectory() &&
(Registry.is("filesystem.useNative"))) {
(!ApplicationManager.getApplication().isUnitTestMode() && Registry.is("filesystem.useNative"))) {
delegate = new Win32LocalFileSystem();
}
@@ -19,7 +19,7 @@ actionSystem.playback.description=Delay between events generated by the playback
actionSystem.focusIdleTimeout=20
actionSystem.mac.screenMenuNotUpdatedFix=false
actionSystem.keyGestures.enabled=false
actionSystem.suspendFocusTransferIfApplicationInactive=true
actionSystem.suspendFocusTransferIfApplicationInactive=false
ide.debugMode=true
ide.debugMode.description=Record additonal information to make bug reports more informative
@@ -39,4 +39,4 @@ ide.tabbedPane.bufferedPaint=true
debugger.valueTooltipAutoShow=true
debugger.valueTooltipAutoShow.description=Auto show tooltip on mouse over
filesystem.useNative=false
filesystem.useNative=true
@@ -0,0 +1,91 @@
package com.intellij.ui;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.basic.BasicRadioButtonUI;
import java.awt.*;
import java.awt.event.*;
/**
* @author oleg
*/
public class CheckBoxList extends JList {
private static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
private static final int DEFAULT_CHECK_BOX_WIDTH = 20;
public CheckBoxList(final ListModel dataModel, final CheckBoxListListener checkBoxListListener) {
super(dataModel);
setCellRenderer(new CellRenderer());
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
setBorder(BorderFactory.createEtchedBorder());
addKeyListener(new KeyAdapter() {
@Override
public void keyTyped(KeyEvent e) {
if (e.getKeyChar() == ' ') {
int index = CheckBoxList.this.getSelectedIndex();
if (index >= 0) {
JCheckBox checkbox = (JCheckBox)getModel().getElementAt(index);
setSelected(checkbox, index, checkBoxListListener);
}
}
}
});
addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (isEnabled()) {
int index = locationToIndex(e.getPoint());
if (index != -1) {
JCheckBox checkbox = (JCheckBox)getModel().getElementAt(index);
int iconArea;
try {
iconArea = ((BasicRadioButtonUI)checkbox.getUI()).getDefaultIcon().getIconWidth();
}
catch (ClassCastException c) {
iconArea = DEFAULT_CHECK_BOX_WIDTH;
}
if (e.getX() < iconArea) {
setSelected(checkbox, index, checkBoxListListener);
}
}
}
}
});
}
private void setSelected(JCheckBox checkbox, int index, CheckBoxListListener checkBoxListListener) {
boolean value = !checkbox.isSelected();
checkbox.setSelected(value);
repaint();
checkBoxListListener.checkBoxSelectionChanged(index, value);
}
private class CellRenderer implements ListCellRenderer {
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
JCheckBox checkbox = (JCheckBox)value;
checkbox.setBackground(getBackgound(isSelected, checkbox));
checkbox.setForeground(getForeGround(isSelected, checkbox));
checkbox.setEnabled(isEnabled());
checkbox.setFont(getFont(checkbox));
checkbox.setFocusPainted(false);
checkbox.setBorderPainted(true);
checkbox.setBorder(isSelected ? UIManager.getBorder("List.focusCellHighlightBorder") : noFocusBorder);
return checkbox;
}
}
protected Font getFont(final JCheckBox checkbox) {
return getFont();
}
protected Color getBackgound(final boolean isSelected, final JCheckBox checkbox) {
return isSelected ? getSelectionBackground() : getBackground();
}
protected Color getForeGround(final boolean isSelected, final JCheckBox checkbox) {
return isSelected ? getSelectionForeground() : getForeground();
}
}
@@ -0,0 +1,8 @@
package com.intellij.ui;
/**
* @author oleg
*/
public interface CheckBoxListListener {
void checkBoxSelectionChanged(int index, boolean value);
}
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.ui.OptionalChooserComponent">
<grid id="27dc6" binding="myContentPane" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="10" left="7" bottom="7" right="7"/>
<constraints>
<xy x="20" y="20" width="455" height="247"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<scrollpane id="4c4f5">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="1e69c" class="com.intellij.ui.CheckBoxList" binding="myList" custom-create="true">
<constraints/>
<properties>
<selectionMode value="0"/>
</properties>
</component>
</children>
</scrollpane>
</children>
</grid>
</form>
@@ -0,0 +1,69 @@
package com.intellij.ui;
import com.intellij.openapi.util.Pair;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.util.ArrayList;
import java.util.List;
/**
* @author oleg
* This component represents a list of checkboxes.
*/
public abstract class OptionalChooserComponent implements CheckBoxListListener {
private JPanel myContentPane;
private CheckBoxList myList;
private DefaultListModel myListModel;
private List<Pair<String, Boolean>> myInitialList;
private ArrayList<Pair<String, Boolean>> myWorkingList;
public OptionalChooserComponent(@NotNull final List<Pair<String, Boolean>> list) {
myInitialList = list;
myWorkingList = new ArrayList<Pair<String, Boolean>>(myInitialList);
// fill list
reset();
}
public JPanel getContentPane() {
return myContentPane;
}
public void checkBoxSelectionChanged(int index, boolean value) {
final Pair<String, Boolean> pair = myWorkingList.remove(index);
myWorkingList.add(index, Pair.create(pair.first, value));
}
private void createUIComponents() {
myListModel = new DefaultListModel();
myList = new CheckBoxList(myListModel, this);
}
public void reset() {
myWorkingList = new ArrayList<Pair<String, Boolean>>(myInitialList);
update();
}
public abstract JCheckBox createCheckBox(final String path, final boolean checked);
public boolean isModified() {
return !myWorkingList.equals(myInitialList);
}
public ArrayList<Pair<String, Boolean>> getValue() {
return myWorkingList;
}
public void apply() {
myInitialList.clear();
myInitialList.addAll(myWorkingList);
}
public void update() {
myListModel.clear();
for (Pair<String, Boolean> pair : myWorkingList) {
myListModel.addElement(createCheckBox(pair.first, pair.second));
}
}
}
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.ui.PathsChooserComponent">
<grid id="27dc6" binding="myContentPane" layout-manager="GridLayoutManager" row-count="3" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="10" left="7" bottom="7" right="7"/>
<constraints>
<xy x="20" y="20" width="591" height="247"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<vspacer id="e6d11">
<constraints>
<grid row="2" column="1" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
<scrollpane id="837a">
<constraints>
<grid row="0" column="0" row-span="3" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="8b3da" class="javax.swing.JList" binding="myList">
<constraints/>
<properties>
<selectionMode value="0"/>
</properties>
</component>
</children>
</scrollpane>
<component id="360f6" class="javax.swing.JButton" binding="myAddButton" default-binding="true">
<constraints>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text resource-bundle="messages/UIBundle" key="row.add"/>
</properties>
</component>
<component id="f80a3" class="javax.swing.JButton" binding="myRemoveButton" default-binding="true">
<constraints>
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text resource-bundle="messages/UIBundle" key="row.remove"/>
</properties>
</component>
</children>
</grid>
</form>
@@ -0,0 +1,101 @@
package com.intellij.ui;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.fileChooser.FileChooserDialog;
import com.intellij.openapi.fileChooser.FileChooserFactory;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
/**
* @author oleg
* This component is used to configure list of folders with add/remove buttons.
*/
public class PathsChooserComponent {
private JPanel myContentPane;
private JList myList;
private JButton myAddButton;
private JButton myRemoveButton;
private DefaultListModel myListModel;
private List<String> myWorkingCollection;
private List<String> myInitialCollection;
public PathsChooserComponent(@NotNull final List<String> collection, @NotNull final PathProcessor processor) {
myInitialCollection = collection;
myWorkingCollection = new ArrayList<String>(myInitialCollection);
myListModel = new DefaultListModel();
myList.setModel(myListModel);
// fill list
reset();
// listeners
myAddButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
final FileChooserDescriptor dirChooser = FileChooserDescriptorFactory.createSingleFolderDescriptor();
dirChooser.setShowFileSystemRoots(true);
dirChooser.setHideIgnored(true);
dirChooser.setTitle(UIBundle.message("file.chooser.default.title"));
FileChooserDialog chooser = FileChooserFactory.getInstance().createFileChooser(dirChooser, myContentPane);
VirtualFile[] files = chooser.choose(null, null);
for (VirtualFile file : files) {
// adding to the end
final String path = file.getPath();
if (processor.addPath(myWorkingCollection, path)){
myListModel.addElement(path);
}
}
}
});
myRemoveButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int selected = myList.getSelectedIndex();
if (selected != -1) {
// removing index
final String path = (String) myListModel.get(selected);
if (processor.removePath(myWorkingCollection, path)){
myListModel.remove(selected);
}
}
}
});
}
public JPanel getContentPane() {
return myContentPane;
}
public List<String> getValues(){
return myWorkingCollection;
}
public void reset() {
myListModel.clear();
myWorkingCollection = new ArrayList<String>(myInitialCollection);
for (String path : myWorkingCollection) {
myListModel.addElement(path);
}
}
public boolean isModified() {
return !myWorkingCollection.equals(myInitialCollection);
}
public void apply() {
myInitialCollection.clear();
myInitialCollection.addAll(myWorkingCollection);
}
public interface PathProcessor {
boolean addPath(List<String> paths, String path);
boolean removePath(List<String> paths, String path);
}
}
+1
View File
@@ -16,6 +16,7 @@
<orderEntry type="module" module-name="platform-resources-en" />
<orderEntry type="library" name="OroMatcher" level="project" />
<orderEntry type="module" module-name="annotations" exported="" />
<orderEntry type="module" module-name="platform-api" />
</component>
<component name="copyright">
<Base>
@@ -26,6 +26,10 @@ import com.intellij.openapi.command.CommandAdapter;
import com.intellij.openapi.command.CommandEvent;
import com.intellij.openapi.command.CommandListener;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootEvent;
import com.intellij.openapi.roots.ModuleRootListener;
@@ -57,6 +61,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
* shows balloon that notifies user about the problem and offers to correct root mapping.
*/
public class GitRootTracker implements VcsListener {
private static final Logger LOG = Logger.getInstance("#git4idea.vfs.GitRootTracker");
/**
* The context project
*/
@@ -169,7 +176,7 @@ public class GitRootTracker implements VcsListener {
}
};
fileManager.addVirtualFileManagerListener(myVirtualFileManagerListener);
StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new Runnable() {
StartupManager.getInstance(myProject).registerPostStartupActivity(new Runnable() {
public void run() {
myIsEnabled.set(true);
checkRoots(true);
@@ -208,94 +215,106 @@ public class GitRootTracker implements VcsListener {
if (!myIsEnabled.get() || (!rootsChanged && !myHasGitRoots.get())) {
return;
}
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
boolean hasInvalidRoots = false;
HashSet<String> rootSet = new HashSet<String>();
for (VcsDirectoryMapping m : myVcsManager.getDirectoryMappings()) {
if (!m.getVcs().equals(myVcs.getName())) {
continue;
ProgressManager.getInstance().run(new Task.Backgroundable(myProject, "Checking unmapped Git roots...") {
@Override
public void run(@NotNull ProgressIndicator indicator) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
public void run() {
LOG.info("Checking unmapped Git roots...");
long start = System.currentTimeMillis();
doCheck();
LOG.info("Unmapped Git roots checked in " + (System.currentTimeMillis() - start) + "ms");
}
String path = m.getDirectory();
if (path.length() == 0) {
VirtualFile baseDir = myProject.getBaseDir();
assert baseDir != null;
path = baseDir.getPath();
}
VirtualFile root = lookupFile(path);
if (root == null) {
hasInvalidRoots = true;
break;
}
else {
rootSet.add(root.getPath());
}
}
if (!hasInvalidRoots && rootSet.isEmpty()) {
myHasGitRoots.set(false);
return;
}
else {
myHasGitRoots.set(true);
}
if (!hasInvalidRoots) {
// check if roots have a problem
loop:
for (String path : rootSet) {
VirtualFile root = lookupFile(path);
VirtualFile gitRoot = GitUtil.gitRootOrNull(root);
if (gitRoot == null || hasUnmappedSubroots(root, rootSet)) {
hasInvalidRoots = true;
break;
}
for (String otherPath : rootSet) {
if (otherPath.equals(path)) {
continue;
}
if (otherPath.startsWith(path)) {
VirtualFile otherFile = lookupFile(otherPath);
if (otherFile == null) {
hasInvalidRoots = true;
break loop;
}
VirtualFile otherRoot = GitUtil.gitRootOrNull(otherFile);
if (otherRoot == null || otherRoot == root || otherFile != otherRoot) {
hasInvalidRoots = true;
break loop;
}
}
}
}
}
if (!hasInvalidRoots) {
// all roots are correct
if (myNotificationPosted.compareAndSet(true, false)) {
if (myNotification != null) {
if (!myNotification.isExpired()) {
myNotification.expire();
}
myNotification = null;
}
}
return;
}
if (myNotificationPosted.compareAndSet(false, true)) {
myNotification = new Notification(GIT_INVALID_ROOTS_ID, GitBundle.getString("root.tracker.message.title"),
GitBundle.getString("root.tracker.message"),
NotificationType.ERROR, new NotificationListener() {
public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
if (fixRoots()) {
notification.expire();
}
}
});
Notifications.Bus.notify(myNotification, myProject);
}
});
myMulticaster.gitRootsChanged();
}
});
myMulticaster.gitRootsChanged();
}
private void doCheck() {
boolean hasInvalidRoots = false;
HashSet<String> rootSet = new HashSet<String>();
for (VcsDirectoryMapping m : myVcsManager.getDirectoryMappings()) {
if (!m.getVcs().equals(myVcs.getName())) {
continue;
}
String path = m.getDirectory();
if (path.length() == 0) {
VirtualFile baseDir = myProject.getBaseDir();
assert baseDir != null;
path = baseDir.getPath();
}
VirtualFile root = lookupFile(path);
if (root == null) {
hasInvalidRoots = true;
break;
}
else {
rootSet.add(root.getPath());
}
}
if (!hasInvalidRoots && rootSet.isEmpty()) {
myHasGitRoots.set(false);
return;
}
else {
myHasGitRoots.set(true);
}
if (!hasInvalidRoots) {
// check if roots have a problem
loop:
for (String path : rootSet) {
VirtualFile root = lookupFile(path);
VirtualFile gitRoot = GitUtil.gitRootOrNull(root);
if (gitRoot == null || hasUnmappedSubroots(root, true, rootSet)) {
hasInvalidRoots = true;
break;
}
for (String otherPath : rootSet) {
if (otherPath.equals(path)) {
continue;
}
if (otherPath.startsWith(path)) {
VirtualFile otherFile = lookupFile(otherPath);
if (otherFile == null) {
hasInvalidRoots = true;
break loop;
}
VirtualFile otherRoot = GitUtil.gitRootOrNull(otherFile);
if (otherRoot == null || otherRoot == root || otherFile != otherRoot) {
hasInvalidRoots = true;
break loop;
}
}
}
}
}
if (!hasInvalidRoots) {
// all roots are correct
if (myNotificationPosted.compareAndSet(true, false)) {
if (myNotification != null) {
if (!myNotification.isExpired()) {
myNotification.expire();
}
myNotification = null;
}
}
return;
}
if (myNotificationPosted.compareAndSet(false, true)) {
myNotification = new Notification(GIT_INVALID_ROOTS_ID, GitBundle.getString("root.tracker.message.title"),
GitBundle.getString("root.tracker.message"),
NotificationType.ERROR, new NotificationListener() {
public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
if (fixRoots()) {
notification.expire();
}
}
});
Notifications.Bus.notify(myNotification, myProject);
}
}
/**
@@ -305,15 +324,14 @@ public class GitRootTracker implements VcsListener {
* @param rootSet the mapped root set
* @return true if there are unmapped subroots
*/
private static boolean hasUnmappedSubroots(VirtualFile directory, HashSet<String> rootSet) {
private static boolean hasUnmappedSubroots(VirtualFile directory, boolean isRoot, HashSet<String> rootSet) {
for (VirtualFile child : directory.getChildren()) {
if (child.getName().equals(".git") || !child.isDirectory()) {
continue;
if (child.getName().equals(".git")) {
if (isRoot || !child.isDirectory())
continue;
return !rootSet.contains(directory.getPath());
}
if (child.findChild(".git") != null && !rootSet.contains(child.getPath())) {
return true;
}
if (hasUnmappedSubroots(child, rootSet)) {
if (child.isDirectory() && hasUnmappedSubroots(child, false, rootSet)) {
return true;
}
}
@@ -25,6 +25,7 @@ import java.util.*;
class FilterCache {
private final ArrayList<TestProxy> myList = new ArrayList<TestProxy>(4);
private final Set<TestProxy> mySet = new HashSet<TestProxy>();
private final Map<Filter, ArrayList<TestProxy>> myCache = new THashMap<Filter, ArrayList<TestProxy>>();
public TestProxy[] select(final Filter filter) {
@@ -46,9 +47,14 @@ class FilterCache {
public void add(final TestProxy test) {
myList.add(test);
mySet.add(test);
resetCache();
}
public boolean contains(TestProxy test) {
return mySet.contains(test);
}
public AbstractTestProxy detect(final Filter filter) {
return filter.detectIn(myList);
}
@@ -83,7 +83,7 @@ public class SuiteState extends TestState {
return myCache.get(ALL_TESTS);
}
public void changeStateAfterAddingChaildTo(final TestProxy test, final TestProxy child) {
public void changeStateAfterAddingChildTo(final TestProxy test, final TestProxy child) {
if (child.getState().getMagnitude() <= getMagnitude()) {
test.onStatisticsChanged();
return;
@@ -102,7 +102,6 @@ public class TestProxy extends CompositePrintable implements PrintableTestProxy,
pullEvent(new StateChangedEvent(this));
if (myParent != null)
myParent.onChanged(this);
fireStatisticsChanged();
myNotifier.onChanged(this);
}
@@ -163,7 +162,7 @@ public class TestProxy extends CompositePrintable implements PrintableTestProxy,
}
public void addChild(final TestProxy child) {
if (myChildren.getList().contains(child))
if (myChildren.contains(child))
return;
if (child.getParent() != null)
return;//todo throw new RuntimeException("Test: "+child + " already has parent: " + child.getParent());
@@ -174,8 +173,7 @@ public class TestProxy extends CompositePrintable implements PrintableTestProxy,
child.fireOnNewPrintable(child);
}
pullEvent(new NewChildEvent(this, child));
fireStatisticsChanged();
getState().changeStateAfterAddingChaildTo(this, child);
getState().changeStateAfterAddingChildTo(this, child);
myNotifier.onChildAdded(this, child);
}
@@ -203,11 +201,6 @@ public class TestProxy extends CompositePrintable implements PrintableTestProxy,
}
public void onStatisticsChanged() {
myChildren.resetCache();
fireStatisticsChanged();
}
private void fireStatisticsChanged() {
myChildren.resetCache();
if (myParent != null)
myParent.onStatisticsChanged();
@@ -220,12 +213,11 @@ public class TestProxy extends CompositePrintable implements PrintableTestProxy,
}
public void setStatistics(final Statistics statistics) {
myChildren.resetCache();
if (!myState.isFinal()) {
LOG.error("" + myState.getMagnitude());
LOG.error(String.valueOf(myState.getMagnitude()));
}
myStatistics = statistics;
fireStatisticsChanged();
onStatisticsChanged();
}
public Statistics getStatisticsImpl() {
@@ -65,7 +65,7 @@ public abstract class TestState implements Printable {
return null;
}
public void changeStateAfterAddingChaildTo(final TestProxy test, final TestProxy child) {
public void changeStateAfterAddingChildTo(final TestProxy test, final TestProxy child) {
test.setState(new SuiteState(test));
}
}
@@ -113,7 +113,7 @@ public class TestStateUpdater implements PacketConsumer {
final List<TestProxy> children = parent.getChildren();
final TestState parentState = parent.getState();
LOG.assertTrue(parentState instanceof SuiteState);
if (children.indexOf(child) == children.size() - 1) {
if (child.equals(children.get(children.size() - 1))) {
((SuiteState)parentState).setRunning(false);
}
((SuiteState)parentState).updateMagnitude(magnitude);
@@ -16,8 +16,6 @@
package com.intellij.execution.junit2.ui;
import com.intellij.execution.junit2.NewChildEvent;
import com.intellij.execution.junit2.StatisticsChanged;
import com.intellij.execution.junit2.TestEvent;
import com.intellij.execution.junit2.TestProxy;
import com.intellij.execution.junit2.ui.actions.TestContext;
@@ -70,9 +68,9 @@ class StatisticsPanel extends JPanel implements DataProvider{
myTable.setVisible(true);
// myTestCaseInfo.setVisible(false);
if (myCurrentTest.isLeaf() && myCurrentTest.getParent() != null) {
myChildInfo.onSelectionChanged(myCurrentTest.getParent());
myChildInfo.updateStatistics(myCurrentTest.getParent());
} else{
myChildInfo.onSelectionChanged(myCurrentTest);
myChildInfo.updateStatistics(myCurrentTest);
}
final int idx = myChildInfo.getIndexOf(myCurrentTest);
TableUtil.selectRows(myTable, new int[]{idx});
@@ -99,13 +97,7 @@ class StatisticsPanel extends JPanel implements DataProvider{
private class MyJUnitListener extends JUnitAdapter {
public void onTestChanged(final TestEvent event) {
if (!StatisticsPanel.this.isShowing()) return;
if (event instanceof StatisticsChanged) {
if (myCurrentTest == event.getSource())
updateStatistics();
} else if (event instanceof NewChildEvent) {
if (event.getSource() == myCurrentTest && !myTable.isVisible())
updateStatistics();
}
if (myCurrentTest == event.getSource()) updateStatistics();
}
public void onTestSelected(final TestProxy test) {
@@ -47,8 +47,7 @@ public class StatisticsTable extends ListTableModel {
private void setTest(final TestProxy test) {
if (myTest == test) return;
myTest = test;
changeTableData();
updateStatistics(test);
}
private void changeTableData() {
@@ -102,4 +101,9 @@ public class StatisticsTable extends ListTableModel {
}
return -1;
}
public void updateStatistics(TestProxy currentTest) {
myTest = currentTest;
changeTableData();
}
}
@@ -23,12 +23,12 @@ import com.intellij.execution.junit2.segments.DispatchListener;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.util.Alarm;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class JUnitListenersNotifier implements JUnitListener, TestEventsConsumer, DispatchListener, Runnable {
private static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit2.ui.model.JUnitListenersNotifier");
@@ -142,7 +142,7 @@ public class JUnitListenersNotifier implements JUnitListener, TestEventsConsumer
private void dispatchAllEvents() {
//long start = System.currentTimeMillis();
final List<TestEvent> filteredEvents = removeDuplicatesFromEnd(myEventsQueue);
final List<TestEvent> filteredEvents = removeDuplicates(myEventsQueue);
myEventsQueue.clear();
// MEASURER.start(DISPATCH_SINGLES);
for (final TestEvent event : filteredEvents) {
@@ -153,11 +153,14 @@ public class JUnitListenersNotifier implements JUnitListener, TestEventsConsumer
//System.out.println("duration = " + (System.currentTimeMillis() - start));
}
public static <T> List<T> removeDuplicatesFromEnd(final List<T> list) {
ArrayList<T> result = new ArrayList<T>(list);
Collections.reverse(result);
ContainerUtil.removeDuplicates(result);
Collections.reverse(result);
private static <T> List<T> removeDuplicates(final List<T> list) {
final ArrayList<T> result = new ArrayList<T>(list.size());
final Set<T> collected = new HashSet<T>();
for (T t : list) {
if (collected.contains(t)) continue;
collected.add(t);
result.add(t);
}
return result;
}
}
+3 -3
View File
@@ -48,11 +48,11 @@
<extensions defaultExtensionNs="com.intellij">
<errorHandler implementation="com.intellij.diagnostic.ITNReporter"/>
<projectService serviceInterface="com.intellij.spellchecker.options.SpellCheckerConfiguration"
serviceImplementation="com.intellij.spellchecker.options.SpellCheckerConfiguration"/>
<projectService serviceInterface="com.intellij.spellchecker.settings.SpellCheckerSettings"
serviceImplementation="com.intellij.spellchecker.settings.SpellCheckerSettings"/>
<projectService serviceInterface="com.intellij.spellchecker.SpellCheckerManager"
serviceImplementation="com.intellij.spellchecker.SpellCheckerManager"/>
<projectConfigurable implementation="com.intellij.spellchecker.options.SpellCheckerConfigurable"/>
<projectConfigurable implementation="com.intellij.spellchecker.settings.SpellCheckerSettingsManager"/>
<inspectionToolProvider
@@ -0,0 +1,80 @@
/*
* Copyright 2000-2009 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.spellchecker;
import com.intellij.psi.codeStyle.NameUtil;
import com.intellij.spellchecker.engine.SuggestionProvider;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class BaseSuggestionProvider implements SuggestionProvider {
private final SpellCheckerManager manager;
public BaseSuggestionProvider(@NotNull SpellCheckerManager manager) {
this.manager = manager;
}
@NotNull
public List<String> getSuggestions(@NotNull String text) {
String[] words = NameUtil.nameToWords(text);
int index = 0;
List[] res = new List[words.length];
int i = 0;
for (String word : words) {
int start = text.indexOf(word, index);
int end = start + word.length();
if (!manager.hasProblem(word)) {
List<String> variants = new ArrayList<String>();
variants.add(word);
res[i++] = variants;
}
else {
List<String> variants = manager.getRawSuggestions(word);
res[i++] = variants;
}
index = end;
}
String[] all = null;
int[] counter = new int[i];
int size = 1;
for (int j = 0; j < i; j++) {
size *= res[j].size();
}
all = new String[size];
for (int k = 0; k < size; k++) {
for (int j = 0; j < i; j++) {
if (all[k] == null) {
all[k] = "";
}
all[k] += res[j].get(counter[j]);
counter[j]++;
if (counter[j] >= res[j].size()) {
counter[j] = 0;
}
}
}
return Arrays.asList(all);
}
}
@@ -15,42 +15,45 @@
*/
package com.intellij.spellchecker;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.spellchecker.dictionary.Loader;
import com.intellij.spellchecker.dictionary.Processor;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import java.io.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class FileLoader implements Loader {
private String url;
private static final Logger LOG = Logger.getInstance("#com.intellij.spellchecker.FileLoader");
public FileLoader(String url) {
this.url = url;
private String url;
public FileLoader(String url) {
this.url = url;
}
public void load(@NotNull Consumer<String> consumer) {
File file = new File(url);
FileInputStream stream = null;
try {
stream = new FileInputStream(file);
StreamLoader loader = new StreamLoader(stream);
loader.load(consumer);
}
public void load(@NotNull Processor processor) {
InputStream io = SpellCheckerManager.class.getResourceAsStream(url);
DataInputStream in = new DataInputStream(io);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
try{
String strLine;
while ((strLine = br.readLine()) != null) {
processor.process(strLine);
}
in.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
br.close();
}
catch (IOException ignored) {
}
}
catch (Exception e) {
LOG.error(e);
}
finally {
try {
stream.close();
}
catch (IOException ignored) {
}
}
}
}
@@ -25,8 +25,12 @@ import com.intellij.spellchecker.dictionary.Dictionary;
import com.intellij.spellchecker.dictionary.Loader;
import com.intellij.spellchecker.engine.SpellCheckerEngine;
import com.intellij.spellchecker.engine.SpellCheckerFactory;
import com.intellij.spellchecker.engine.SuggestionProvider;
import com.intellij.spellchecker.settings.SpellCheckerSettings;
import com.intellij.spellchecker.state.StateLoader;
import com.intellij.spellchecker.util.SPFileUtil;
import com.intellij.spellchecker.util.Strings;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -43,13 +47,26 @@ public class SpellCheckerManager {
private Dictionary userDictionary;
private final String[] bundledDictionaries = new String[]{"english.dic", "jetbrains.dic"};
@NotNull
private final SuggestionProvider suggestionProvider = new BaseSuggestionProvider(this);
private final SpellCheckerSettings settings;
public static SpellCheckerManager getInstance(Project project) {
return ServiceManager.getService(project, SpellCheckerManager.class);
}
public SpellCheckerManager(Project project) {
public SpellCheckerManager(Project project, SpellCheckerSettings settings) {
this.project = project;
this.settings = settings;
reloadConfiguration();
}
public Project getProject() {
return project;
}
public Dictionary getUserDictionary() {
@@ -64,7 +81,26 @@ public class SpellCheckerManager {
private void fillEngineDictionary() {
spellChecker.reset();
final StateLoader stateLoader = new StateLoader(project);
Loader[] loaders = new Loader[]{new FileLoader("english.dic"), new FileLoader("jetbrains.dic"), stateLoader};
final List<Loader> loaders = new ArrayList<Loader>();
for (String dictionary : bundledDictionaries) {
if (this.settings == null || !this.settings.getBundledDisabledDictionariesPaths().contains(dictionary)) {
loaders.add(new StreamLoader(SpellCheckerManager.class.getResourceAsStream(dictionary)));
}
}
if (this.settings != null && this.settings.getDictionaryFoldersPaths() != null) {
final Set<String> disabledDictionaries = settings.getDisabledDictionariesPaths();
for (String folder : this.settings.getDictionaryFoldersPaths()) {
SPFileUtil.processFilesRecursively(folder, new Consumer<String>() {
public void consume(final String s) {
if (!disabledDictionaries.contains(s)) {
loaders.add(new FileLoader(s));
}
}
});
}
}
loaders.add(stateLoader);
for (Loader loader : loaders) {
spellChecker.loadDictionary(loader);
}
@@ -84,22 +120,31 @@ public class SpellCheckerManager {
}
}
public void updateUserWords(@Nullable Collection<String> words) {
Set<String> transformed = spellChecker.getTransformation().transform(words);
userDictionary.replaceAll(transformed);
fillEngineDictionary();
public void update(@Nullable Collection<String> words, SpellCheckerSettings allDictionaries) {
reloadConfiguration();
restartInspections();
}
@NotNull
public List<String> getBundledDictionaries() {
return (bundledDictionaries != null ? Arrays.asList(bundledDictionaries) : Collections.<String>emptyList());
}
@NotNull
public static HighlightDisplayLevel getHighlightDisplayLevel() {
return HighlightDisplayLevel.find(SpellCheckerSeveritiesProvider.TYPO);
}
@NotNull
public List<String> getSuggestions(@NotNull String word) {
public List<String> getSuggestions(@NotNull String text) {
return suggestionProvider.getSuggestions(text);
}
@NotNull
protected List<String> getRawSuggestions(@NotNull String word) {
if (!spellChecker.isCorrect(word)) {
List<String> suggestions = spellChecker.getSuggestions(word, MAX_SUGGESTIONS_THRESHOLD, MAX_METRICS);
if (suggestions.size() != 0) {
@@ -144,5 +189,4 @@ public class SpellCheckerManager {
}
}
@@ -0,0 +1,59 @@
/*
* Copyright 2000-2009 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.spellchecker;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.spellchecker.dictionary.Loader;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import java.io.*;
public class StreamLoader implements Loader {
private static final Logger LOG = Logger.getInstance("#com.intellij.spellchecker.StreamLoader");
private InputStream stream;
public StreamLoader(InputStream stream) {
this.stream = stream;
}
public void load(@NotNull Consumer<String> consumer) {
DataInputStream in = new DataInputStream(stream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
try {
String strLine;
while ((strLine = br.readLine()) != null) {
consumer.consume(strLine);
}
}
catch (Exception e) {
LOG.error(e);
}
finally {
try {
br.close();
}
catch (IOException ignored) {
}
}
}
}
@@ -15,10 +15,11 @@
*/
package com.intellij.spellchecker.dictionary;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
public interface Loader {
void load(@NotNull Processor processor);
void load(@NotNull Consumer<String> consumer);
}
@@ -15,8 +15,11 @@
*/
package com.intellij.spellchecker.engine;
import com.intellij.spellchecker.dictionary.*;
import com.intellij.spellchecker.dictionary.Dictionary;
import com.intellij.spellchecker.dictionary.Loader;
import com.intellij.spellchecker.dictionary.UserDictionary;
import com.intellij.spellchecker.trie.Action;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -34,8 +37,8 @@ public class BaseSpellChecker implements SpellCheckerEngine {
private Metrics metrics = new LevenshteinDistance();
private Processor processor = new Processor() {
public void process(@Nullable String word) {
private Consumer<String> consumer = new Consumer<String>() {
public void consume(@Nullable String word) {
final String transformed = transform.transform(word);
if (transformed != null) {
engineDictionary.addToDictionary(transformed);
@@ -48,7 +51,7 @@ public class BaseSpellChecker implements SpellCheckerEngine {
}
public void loadDictionary(@NotNull Loader loader) {
loader.load(processor);
loader.load(consumer);
}
public Transformation getTransformation() {
@@ -16,10 +16,12 @@
package com.intellij.spellchecker.engine;
public final class SpellCheckerFactory {
private SpellCheckerFactory() {
}
private SpellCheckerFactory() {
}
public static SpellCheckerEngine create() {
return new BaseSpellChecker();
}
public static SpellCheckerEngine create() {
return new BaseSpellChecker();
}
}
@@ -13,11 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.spellchecker.dictionary;
package com.intellij.spellchecker.engine;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.NotNull;
public interface Processor {
import java.util.List;
void process(@Nullable String word);
public interface SuggestionProvider {
@NotNull
List<String> getSuggestions(@NotNull String text);
}
@@ -49,6 +49,9 @@ import java.util.Map;
public class SpellCheckingInspection extends LocalInspectionTool {
public static final String SPELL_CHECKING_INSPECTION_TOOL_NAME = "SpellCheckingInspection";
@Nls
@NotNull
public String getGroupDisplayName() {
@@ -64,7 +67,7 @@ public class SpellCheckingInspection extends LocalInspectionTool {
@NonNls
@NotNull
public String getShortName() {
return "SpellCheckingInspection";
return SPELL_CHECKING_INSPECTION_TOOL_NAME;
}
public boolean isEnabledByDefault() {
@@ -79,19 +82,19 @@ public class SpellCheckingInspection extends LocalInspectionTool {
private static final Map<Language, SpellcheckingStrategy> factories = new HashMap<Language, SpellcheckingStrategy>();
private static void ensureFactoriesAreLoaded() {
synchronized (factories) {
if (!factories.isEmpty()) return;
final SpellcheckingStrategy[] spellcheckingStrategies = Extensions.getExtensions(SpellcheckingStrategy.EP_NAME);
if (spellcheckingStrategies != null) {
for (SpellcheckingStrategy spellcheckingStrategy : spellcheckingStrategies) {
final Language language = spellcheckingStrategy.getLanguage();
if (language != Language.ANY) {
factories.put(language, spellcheckingStrategy);
}
synchronized (factories) {
if (!factories.isEmpty()) return;
final SpellcheckingStrategy[] spellcheckingStrategies = Extensions.getExtensions(SpellcheckingStrategy.EP_NAME);
if (spellcheckingStrategies != null) {
for (SpellcheckingStrategy spellcheckingStrategy : spellcheckingStrategies) {
final Language language = spellcheckingStrategy.getLanguage();
if (language != Language.ANY) {
factories.put(language, spellcheckingStrategy);
}
}
}
}
}
private static SpellcheckingStrategy getFactoryByLanguage(@NotNull Language lang) {
@@ -106,7 +109,7 @@ public class SpellCheckingInspection extends LocalInspectionTool {
public void visitElement(final PsiElement element) {
final ASTNode node = element.getNode();
if (node == null){
if (node == null) {
return;
}
// Extract parser definition from element
@@ -115,17 +118,18 @@ public class SpellCheckingInspection extends LocalInspectionTool {
final ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(language);
// Handle selected options
if (parserDefinition != null){
if (parserDefinition != null) {
if (parserDefinition.getStringLiteralElements().contains(elementType)) {
if (!processLiterals){
if (!processLiterals) {
return;
}
}
else if (parserDefinition.getCommentTokens().contains(elementType)) {
if (!processComments){
if (!processComments) {
return;
}
} else if (!processCode){
}
else if (!processCode) {
return;
}
}
@@ -246,6 +250,18 @@ public class SpellCheckingInspection extends LocalInspectionTool {
verticalBox.add(new SingleCheckboxOptionsPanel(SpellCheckerBundle.message("process.code"), this, "processCode"));
verticalBox.add(new SingleCheckboxOptionsPanel(SpellCheckerBundle.message("process.literals"), this, "processLiterals"));
verticalBox.add(new SingleCheckboxOptionsPanel(SpellCheckerBundle.message("process.comments"), this, "processComments"));
/*HyperlinkLabel linkToSettings = new HyperlinkLabel(SpellCheckerBundle.message("link.to.settings"));
linkToSettings.addHyperlinkListener(new HyperlinkListener() {
public void hyperlinkUpdate(final HyperlinkEvent e) {
if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
final OptionsEditor optionsEditor = OptionsEditor.KEY.getData(DataManager.getInstance().getDataContext());
// ??project?
}
}
});
verticalBox.add(linkToSettings);*/
final JPanel panel = new JPanel(new BorderLayout());
panel.add(verticalBox, BorderLayout.NORTH);
return panel;
@@ -91,6 +91,7 @@ dirs
fileset
filesets
javadoc
spellchecker
spellchecking
@@ -1,102 +0,0 @@
/*
* Copyright 2000-2009 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.spellchecker.options;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.spellchecker.SpellCheckerManager;
import com.intellij.spellchecker.util.SpellCheckerBundle;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.List;
import java.util.Set;
public final class SpellCheckerConfigurable implements Configurable {
private SpellCheckerOptions options;
private SpellCheckerManager manager;
private final Project myProject;
public SpellCheckerConfigurable(Project project) {
myProject = project;
}
@Nls
public String getDisplayName() {
return SpellCheckerBundle.message("spelling");
}
@Nullable
public Icon getIcon() {
return null;
}
@Nullable
@NonNls
public String getHelpTopic() {
return "reference.settings.ide.settings.spelling";
}
public JComponent createComponent() {
manager = SpellCheckerManager.getInstance(myProject);
if (options == null) {
options = new SpellCheckerOptions(manager);
}
return options.getRoot();
}
public boolean isModified() {
if (options != null) {
return wordsListIsModified();
}
return false;
}
private boolean wordsListIsModified() {
assert options != null;
List<String> newWords = options.getWords();
Set<String> words = manager.getUserDictionary().getEditableWords();
if (words == null && newWords == null) {
return false;
}
if (words == null || newWords == null || newWords.size() != words.size()) {
return true;
}
return !(words.containsAll(newWords) && newWords.containsAll(words));
}
public void apply() throws ConfigurationException {
manager.updateUserWords(options.getWords());
}
public void reset() {
}
public void disposeUIResources() {
if (options != null) {
options.dispose();
options = null;
}
}
}
@@ -1,46 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.spellchecker.options.SpellCheckerOptions">
<grid id="27dc6" binding="root" default-binding="true" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="387" height="285"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<hspacer id="f0925">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
</hspacer>
<grid id="37249" binding="wordPanelHolder" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<grid id="dda13" class="com.intellij.spellchecker.options.SpellCheckerOptions$WordsPanel" binding="wordsPanel" custom-create="true" layout-manager="BorderLayout" hgap="0" vgap="0">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children/>
</grid>
</children>
</grid>
</children>
</grid>
<buttonGroups>
<group name="additionalDic">
<member id="76b15"/>
<member id="4ba70"/>
</group>
</buttonGroups>
<inspectionSuppressions>
<suppress inspection="NoLabelFor" id="253a1"/>
<suppress inspection="NoLabelFor" id="32995"/>
</inspectionSuppressions>
</form>
@@ -1,169 +0,0 @@
/*
* Copyright 2000-2009 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.spellchecker.options;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.ui.Messages;
import com.intellij.spellchecker.SpellCheckerManager;
import com.intellij.spellchecker.dictionary.Dictionary;
import com.intellij.spellchecker.util.SpellCheckerBundle;
import com.intellij.spellchecker.util.Strings;
import com.intellij.ui.AddDeleteListPanel;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
public class SpellCheckerOptions implements Disposable {
private final SpellCheckerManager manager;
private JPanel root;
private JPanel wordPanelHolder;
private WordsPanel wordsPanel;
public SpellCheckerOptions(SpellCheckerManager manager) {
this.manager = manager;
}
public void createUIComponents() {
wordsPanel = new WordsPanel(manager);
}
public JPanel getRoot() {
return root;
}
@Nullable
public List<String> getWords(){
Object[] pairs = wordsPanel.getListItems();
if (pairs==null){
return null;
}
List<String> words = new ArrayList<String>();
for (Object pair : pairs) {
words.add(pair.toString());
}
return words;
}
public void dispose() {
wordsPanel.dispose();
}
public static final class WordDescriber {
private Dictionary dictionary;
public WordDescriber(Dictionary dictionary) {
this.dictionary = dictionary;
}
@NotNull
public List<Pair> process() {
if (this.dictionary == null) {
return new ArrayList<Pair>();
}
Set<String> words = this.dictionary.getEditableWords();
if (words == null) {
return new ArrayList<Pair>();
}
List<Pair> result = new ArrayList<Pair>();
for (String word : words) {
result.add(new Pair(word, ""));
}
Collections.sort(result);
return result;
}
}
public static final class Pair implements Comparable {
private String word;
private String description;
public Pair(@NotNull String word, String description) {
this.word = word;
this.description = description;
}
public String getWord() {
return word;
}
public String getDescription() {
return description;
}
public int compareTo(Object o) {
if (!(o instanceof Pair)) {
throw new IllegalArgumentException();
}
return word.compareTo(((Pair)o).getWord());
}
@Override
public String toString() {
return word + (description!=null && description.trim().length()>0?"("+description+")":"");
}
}
private static final class WordsPanel extends AddDeleteListPanel implements Disposable {
private SpellCheckerManager manager;
private WordsPanel(SpellCheckerManager manager) {
super(null, new WordDescriber(manager.getUserDictionary()).process());
this.manager = manager;
}
protected Object findItemToAdd() {
String word = Messages.showInputDialog(com.intellij.spellchecker.util.SpellCheckerBundle.message("enter.simple.word"),
SpellCheckerBundle.message("add.new.word"), null);
if (word == null) {
return null;
}
else {
word = word.trim();
}
if (Strings.isMixedCase(word)) {
Messages.showWarningDialog(SpellCheckerBundle.message("entered.word.0.is.mixed.cased.you.must.enter.simple.word", word),
SpellCheckerBundle.message("add.new.word"));
return null;
}
if (!manager.hasProblem(word)) {
Messages.showWarningDialog(SpellCheckerBundle.message("entered.word.0.is.correct.you.no.need.to.add.this.in.list", word),
SpellCheckerBundle.message("add.new.word"));
return null;
}
return word;
}
public void dispose() {
myListModel.removeAllElements();
}
}
}
@@ -18,12 +18,14 @@ package com.intellij.spellchecker.quickfixes;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.codeStyle.NameUtil;
import com.intellij.psi.codeStyle.SuggestedNameInfo;
import com.intellij.refactoring.rename.NameSuggestionProvider;
import com.intellij.spellchecker.SpellCheckerManager;
import java.util.*;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
public class DictionarySuggestionProvider implements NameSuggestionProvider {
@@ -49,49 +51,8 @@ public class DictionarySuggestionProvider implements NameSuggestionProvider {
SpellCheckerManager manager = SpellCheckerManager.getInstance(element.getProject());
String[] words = NameUtil.nameToWords(text);
int index = 0;
List[] res = new List[words.length];
int i = 0;
for (String word : words) {
int start = text.indexOf(word, index);
int end = start + word.length();
if (!manager.hasProblem(word)) {
List<String> variants = new ArrayList<String>();
variants.add(word);
res[i++] = variants;
}
else {
List<String> variants = manager.getSuggestions(word);
res[i++] = variants;
}
index = end;
}
String[] all = null;
int counter[] = new int[i];
int size = 1;
for (int j = 0; j < i; j++) {
size *= res[j].size();
}
all = new String[size];
for (int k = 0; k < size; k++) {
for (int j = 0; j < i; j++) {
if (all[k] == null) {
all[k] = "";
}
all[k] += res[j].get(counter[j]);
counter[j]++;
if (counter[j] >= res[j].size()) {
counter[j] = 0;
}
}
}
Set<String> set = new TreeSet<String>();
set.addAll(Arrays.asList(all));
set.addAll(manager.getSuggestions(text));
result.addAll(set);
return null;
}
@@ -35,8 +35,6 @@ public abstract class ShowSuggestions implements LocalQuickFix, Iconable {
private boolean processed;
public ShowSuggestions(@NotNull TextRange textRange, @NotNull String word, @NotNull Project project) {
this.textRange = textRange;
this.word = word;
@@ -0,0 +1,167 @@
/*
* Copyright 2000-2009 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.spellchecker.settings;
import com.intellij.openapi.components.*;
import com.intellij.openapi.project.Project;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import java.util.*;
@State(
name = "SpellCheckerSettings",
storages = {@Storage(
id = "other",
file = "$PROJECT_FILE$"),
@Storage(
id = "dir",
file = "$PROJECT_CONFIG_DIR$/spellchecker-settings.xml",
scheme = StorageScheme.DIRECTORY_BASED)})
public class SpellCheckerSettings implements PersistentStateComponent<Element> {
// For xml serialization
private static final String SPELLCHECKER_MANAGER_SETTINGS_TAG = "SpellCheckerSettings";
private static final String FOLDERS_ATTR_NAME = "Folders";
private static final String FOLDER_ATTR_NAME = "Folder";
private static final String DICTIONARIES_ATTR_NAME = "Dictionaries";
private static final String DICTIONARY_ATTR_NAME = "Dictionary";
private static final String BUNDLED_DICTIONARIES_ATTR_NAME = "BundledDictionaries";
private static final String BUNDLED_DICTIONARY_ATTR_NAME = "BundledDictionary";
// Paths
private List<String> myDictionaryFoldersPaths = new ArrayList<String>();
private Set<String> myDisabledDictionariesPaths = new HashSet<String>();
private Set<String> myBundledDisabledDictionariesPaths = new HashSet<String>();
public static SpellCheckerSettings getInstance(Project project){
return ServiceManager.getService(project,SpellCheckerSettings.class);
}
public List<String> getDictionaryFoldersPaths() {
return myDictionaryFoldersPaths;
}
public void setDictionaryFoldersPaths(List<String> dictionaryFoldersPaths) {
myDictionaryFoldersPaths = dictionaryFoldersPaths;
}
public Set<String> getDisabledDictionariesPaths() {
return myDisabledDictionariesPaths;
}
public Set<String> getEnabledDictionariesPaths() {
final HashSet<String> enabledDictionaries = new HashSet<String>();
for (String folder : myDictionaryFoldersPaths) {
/*RFileUtil.processFilesRecursively(folder, new Consumer<String>() {
public void consume(final String s) {
if (!myDisabledDictionariesPaths.contains(s)){
enabledDictionaries.add(s);
}
}
});*/
}
return enabledDictionaries;
}
public Set<String> getBundledEnabledDictionariesPaths() {
final HashSet<String> bundledEnabledDictionaries = new HashSet<String>();
final List<String> builtInFolders = getBundledDictionariesFoldersPaths();
for (String folder : builtInFolders) {
/*RFileUtil.processFilesRecursively(folder, new Consumer<String>() {
public void consume(final String s) {
if (!myBundledDisabledDictionariesPaths.contains(s)){
bundledEnabledDictionaries.add(s);
}
}
});*/
}
return bundledEnabledDictionaries;
}
public void setDisabledDictionariesPaths(Set<String> disabledDictionariesPaths) {
myDisabledDictionariesPaths = disabledDictionariesPaths;
}
public List<String> getBundledDictionariesFoldersPaths() {
/*return Collections.unmodifiableList(RubySupportLoader.getBuiltinScriptFolders());*/
return Collections.emptyList();
}
public Set<String> getBundledDisabledDictionariesPaths() {
return myBundledDisabledDictionariesPaths;
}
public void setBundledDisabledDictionariesPaths(Set<String> bundledDisabledDictionariesPaths) {
myBundledDisabledDictionariesPaths = bundledDisabledDictionariesPaths;
}
public Element getState() {
final Element element = new Element(SPELLCHECKER_MANAGER_SETTINGS_TAG);
// bundled
element.setAttribute(BUNDLED_DICTIONARIES_ATTR_NAME, String.valueOf(myBundledDisabledDictionariesPaths.size()));
Iterator<String> iterator = myBundledDisabledDictionariesPaths.iterator();
int i=0;
while (iterator.hasNext()){
element.setAttribute(BUNDLED_DICTIONARY_ATTR_NAME + i, iterator.next());
i++;
}
// user
element.setAttribute(FOLDERS_ATTR_NAME, String.valueOf(myDictionaryFoldersPaths.size()));
for (int j=0;j< myDictionaryFoldersPaths.size();j++){
element.setAttribute(FOLDER_ATTR_NAME + j, myDictionaryFoldersPaths.get(j));
}
element.setAttribute(DICTIONARIES_ATTR_NAME, String.valueOf(myDisabledDictionariesPaths.size()));
iterator = myDisabledDictionariesPaths.iterator();
i=0;
while (iterator.hasNext()){
element.setAttribute(DICTIONARY_ATTR_NAME + i, iterator.next());
i++;
}
return element;
}
public void loadState(@NotNull final Element element) {
myBundledDisabledDictionariesPaths.clear();
myDictionaryFoldersPaths.clear();
myDisabledDictionariesPaths.clear();
try {
// bundled
final int bundledDictionariesSize = Integer.valueOf(element.getAttributeValue(BUNDLED_DICTIONARIES_ATTR_NAME));
for (int i=0;i<bundledDictionariesSize;i++){
myBundledDisabledDictionariesPaths.add(element.getAttributeValue(BUNDLED_DICTIONARY_ATTR_NAME + i));
}
// user
final int foldersSize = Integer.valueOf(element.getAttributeValue(FOLDERS_ATTR_NAME));
for (int i=0;i<foldersSize;i++){
myDictionaryFoldersPaths.add(element.getAttributeValue(FOLDER_ATTR_NAME + i));
}
final int scriptsSize = Integer.valueOf(element.getAttributeValue(DICTIONARIES_ATTR_NAME));
for (int i=0;i<scriptsSize;i++){
myDisabledDictionariesPaths.add(element.getAttributeValue(DICTIONARY_ATTR_NAME + i));
}
}
catch (Exception e) {
// ignore
}
}
}
@@ -0,0 +1,86 @@
/*
* Copyright 2000-2009 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.spellchecker.settings;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project;
import com.intellij.spellchecker.util.SpellCheckerBundle;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
public class SpellCheckerSettingsManager implements Configurable {
private SpellCheckerSettingsPane settingsPane;
private SpellCheckerSettings settings;
private Project project;
public static SpellCheckerSettingsManager getInstance(Project project) {
return ShowSettingsUtil.getInstance().findProjectConfigurable(project, SpellCheckerSettingsManager.class);
}
public SpellCheckerSettingsManager(Project project) {
this.project = project;
settings = SpellCheckerSettings.getInstance(project);
}
@Nls
public String getDisplayName() {
return SpellCheckerBundle.message("spelling");
}
@Nullable
public Icon getIcon() {
return null;
}
@Nullable
@NonNls
public String getHelpTopic() {
return "reference.settings.ide.settings.spelling";
}
public JComponent createComponent() {
if (settingsPane == null) {
settingsPane = new SpellCheckerSettingsPane(settings,project);
}
return settingsPane.getPane();
}
public boolean isModified() {
return settingsPane == null || settingsPane.isModified();
}
public void apply() throws ConfigurationException {
if (settingsPane != null) {
settingsPane.apply();
}
}
public void reset() {
if (settingsPane != null) {
settingsPane.reset();
}
}
public void disposeUIResources() {
settingsPane = null;
}
}
@@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.spellchecker.settings.SpellCheckerSettingsPane">
<grid id="27dc6" binding="root" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="500" height="400"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<grid id="3de32" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<grid id="439de" binding="linkContainer" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false">
<preferred-size width="24" height="38"/>
</grid>
</constraints>
<properties/>
<border type="none"/>
<children/>
</grid>
</children>
</grid>
<grid id="6126a" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<tabbedpane id="b70bc" default-binding="true">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false">
<preferred-size width="200" height="200"/>
</grid>
</constraints>
<properties/>
<border type="none"/>
<children>
<grid id="ba93e" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<tabbedpane title="Accepted Words"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<grid id="425d4" binding="panelForAcceptedWords" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children/>
</grid>
</children>
</grid>
<grid id="b6b2d" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<tabbedpane title="Dictionaries"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<grid id="b9ce9" binding="panelForDictionaryChooser" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="etched" title="Dictionaries"/>
<children/>
</grid>
<grid id="3d135" binding="panelForFolderChooser" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="etched" title="User Dictionaries Path"/>
<children/>
</grid>
</children>
</grid>
</children>
</tabbedpane>
</children>
</grid>
</children>
</grid>
</form>
@@ -0,0 +1,323 @@
/*
* Copyright 2000-2009 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.spellchecker.settings;
import com.intellij.ide.DataManager;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.newEditor.OptionsEditor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.profile.codeInspection.ui.ProjectInspectionToolsConfigurable;
import com.intellij.spellchecker.SpellCheckerManager;
import com.intellij.spellchecker.dictionary.Dictionary;
import com.intellij.spellchecker.util.SPFileUtil;
import com.intellij.spellchecker.util.SpellCheckerBundle;
import com.intellij.spellchecker.util.Strings;
import com.intellij.ui.AddDeleteListPanel;
import com.intellij.ui.HyperlinkLabel;
import com.intellij.ui.OptionalChooserComponent;
import com.intellij.ui.PathsChooserComponent;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import java.awt.*;
import java.util.*;
import java.util.List;
public class SpellCheckerSettingsPane implements Disposable {
private JPanel root;
private JPanel linkContainer;
private JPanel panelForDictionaryChooser;
private JPanel panelForAcceptedWords;
private JPanel panelForFolderChooser;
private OptionalChooserComponent optionalChooserComponent;
private PathsChooserComponent pathsChooserComponent;
private final List<Pair<String, Boolean>> allDictionaries = new ArrayList<Pair<String, Boolean>>();
private final List<String> dictionariesFolders = new ArrayList<String>();
private final WordsPanel wordsPanel;
private final SpellCheckerManager manager;
private final SpellCheckerSettings settings;
public SpellCheckerSettingsPane(SpellCheckerSettings settings, final Project project) {
this.settings = settings;
manager = SpellCheckerManager.getInstance(project);
HyperlinkLabel link = new HyperlinkLabel(SpellCheckerBundle.message("link.to.inspection.settings"));
link.addHyperlinkListener(new HyperlinkListener() {
public void hyperlinkUpdate(final HyperlinkEvent e) {
if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
final OptionsEditor optionsEditor = OptionsEditor.KEY.getData(DataManager.getInstance().getDataContext());
final ProjectInspectionToolsConfigurable toolsConfigurable = ProjectInspectionToolsConfigurable.getInstance(project);
if (optionsEditor != null && toolsConfigurable != null) {
optionsEditor.select(toolsConfigurable).doWhenDone(new Runnable() {
public void run() {
toolsConfigurable.selectInspectionTool("SpellCheckingInspection");
}
});
}
}
}
});
linkContainer.setLayout(new BorderLayout());
linkContainer.add(link);
// Fill in all the dictionaries folders (not implemented yet) and enabled dictionaries
fillAllDictionaries();
pathsChooserComponent = new PathsChooserComponent(dictionariesFolders, new PathsChooserComponent.PathProcessor() {
public boolean addPath(List<String> paths, String path) {
if (paths.contains(path)) {
final String title = SpellCheckerBundle.message("add.directory.title");
final String msg = SpellCheckerBundle.message("directory.is.already.included");
Messages.showErrorDialog(root, msg, title);
return false;
}
paths.add(path);
final ArrayList<Pair<String, Boolean>> currentDictionaries = optionalChooserComponent.getValue();
SPFileUtil.processFilesRecursively(path, new Consumer<String>() {
public void consume(final String s) {
currentDictionaries.add(Pair.create(s, true));
}
});
optionalChooserComponent.update();
return true;
}
public boolean removePath(List<String> paths, String path) {
if (paths.remove(path)) {
final ArrayList<Pair<String, Boolean>> result = new ArrayList<Pair<String, Boolean>>();
final ArrayList<Pair<String, Boolean>> currentDictionaries = optionalChooserComponent.getValue();
for (Pair<String, Boolean> pair : currentDictionaries) {
if (!pair.first.startsWith(path)) {
result.add(pair);
}
}
currentDictionaries.clear();
currentDictionaries.addAll(result);
optionalChooserComponent.update();
return true;
}
return false;
}
});
panelForFolderChooser.setLayout(new BorderLayout());
panelForFolderChooser.add(pathsChooserComponent.getContentPane(), BorderLayout.CENTER);
optionalChooserComponent = new OptionalChooserComponent(allDictionaries) {
@Override
public JCheckBox createCheckBox(String path, boolean checked) {
if (isUserDictionary(path)) {
path = FileUtil.toSystemIndependentName(path);
final int i = path.lastIndexOf('/');
if (i != -1) {
final String name = path.substring(i + 1);
return new JCheckBox("[user] " + name, checked);
}
}
return new JCheckBox("[bundled] " + FileUtil.toSystemDependentName(path), checked);
}
};
panelForDictionaryChooser.setLayout(new BorderLayout());
panelForDictionaryChooser.add(optionalChooserComponent.getContentPane(), BorderLayout.CENTER);
wordsPanel = new WordsPanel(manager);
panelForAcceptedWords.setLayout(new BorderLayout());
panelForAcceptedWords.add(wordsPanel, BorderLayout.CENTER);
}
public JComponent getPane() {
return root;
}
public boolean isModified() {
return wordsPanel.isModified() || optionalChooserComponent.isModified();
}
public void apply() throws ConfigurationException {
optionalChooserComponent.apply();
pathsChooserComponent.apply();
settings.setDictionaryFoldersPaths(pathsChooserComponent.getValues());
final HashSet<String> disabledDictionaries = new HashSet<String>();
final HashSet<String> bundledDisabledDictionaries = new HashSet<String>();
for (Pair<String, Boolean> pair : allDictionaries) {
if (!pair.second) {
final String scriptPath = pair.first;
if (isUserDictionary(scriptPath)) {
disabledDictionaries.add(scriptPath);
}
else {
bundledDisabledDictionaries.add(scriptPath);
}
}
}
settings.setDisabledDictionariesPaths(disabledDictionaries);
settings.setBundledDisabledDictionariesPaths(bundledDisabledDictionaries);
manager.update(wordsPanel.getWords(), settings);
}
private boolean isUserDictionary(final String dictionary) {
boolean isUserDictionary = false;
for (String dictionaryFolder : pathsChooserComponent.getValues()) {
if (dictionary.startsWith(dictionaryFolder)) {
isUserDictionary = true;
break;
}
}
return isUserDictionary;
}
public void reset() {
pathsChooserComponent.reset();
fillAllDictionaries();
optionalChooserComponent.reset();
}
private void fillAllDictionaries() {
dictionariesFolders.clear();
dictionariesFolders.addAll(settings.getDictionaryFoldersPaths());
allDictionaries.clear();
for (String dictionary : manager.getBundledDictionaries()) {
allDictionaries.add(new Pair<String, Boolean>(dictionary, !settings.getBundledDisabledDictionariesPaths().contains(dictionary)));
}
// user
//todo [shkate]: refactoring - SpellCheckerManager contains the same code withing reloadConfiguration()
final Set<String> disabledDictionaries = settings.getDisabledDictionariesPaths();
for (String folder : dictionariesFolders) {
SPFileUtil.processFilesRecursively(folder, new Consumer<String>() {
public void consume(final String s) {
allDictionaries.add(Pair.create(s, !disabledDictionaries.contains(s)));
}
});
}
}
public void dispose() {
if (wordsPanel != null) {
wordsPanel.dispose();
}
}
public static final class WordDescriber {
private Dictionary dictionary;
public WordDescriber(Dictionary dictionary) {
this.dictionary = dictionary;
}
@NotNull
public List<String> process() {
if (this.dictionary == null) {
return new ArrayList<String>();
}
Set<String> words = this.dictionary.getEditableWords();
if (words == null) {
return new ArrayList<String>();
}
List<String> result = new ArrayList<String>();
for (String word : words) {
result.add(word);
}
Collections.sort(result);
return result;
}
}
private static final class WordsPanel extends AddDeleteListPanel implements Disposable {
private SpellCheckerManager manager;
private WordsPanel(SpellCheckerManager manager) {
super(null, new WordDescriber(manager.getUserDictionary()).process());
this.manager = manager;
}
protected Object findItemToAdd() {
String word = Messages.showInputDialog(com.intellij.spellchecker.util.SpellCheckerBundle.message("enter.simple.word"),
SpellCheckerBundle.message("add.new.word"), null);
if (word == null) {
return null;
}
else {
word = word.trim();
}
if (Strings.isMixedCase(word)) {
Messages.showWarningDialog(SpellCheckerBundle.message("entered.word.0.is.mixed.cased.you.must.enter.simple.word", word),
SpellCheckerBundle.message("add.new.word"));
return null;
}
if (!manager.hasProblem(word)) {
Messages.showWarningDialog(SpellCheckerBundle.message("entered.word.0.is.correct.you.no.need.to.add.this.in.list", word),
SpellCheckerBundle.message("add.new.word"));
return null;
}
return word;
}
public void dispose() {
myListModel.removeAllElements();
}
@Nullable
public List<String> getWords() {
Object[] pairs = getListItems();
if (pairs == null) {
return null;
}
List<String> words = new ArrayList<String>();
for (Object pair : pairs) {
words.add(pair.toString());
}
return words;
}
public boolean isModified() {
List<String> newWords = getWords();
Set<String> words = manager.getUserDictionary().getEditableWords();
if (words == null && newWords == null) {
return false;
}
if (words == null || newWords == null || newWords.size() != words.size()) {
return true;
}
return !(words.containsAll(newWords) && newWords.containsAll(words));
}
}
}
@@ -19,7 +19,7 @@ import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.spellchecker.dictionary.Dictionary;
import com.intellij.spellchecker.dictionary.Loader;
import com.intellij.spellchecker.dictionary.Processor;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
@@ -35,7 +35,7 @@ public class StateLoader implements Loader {
}
public void load(@NotNull Processor processor) {
public void load(@NotNull Consumer<String> consumer) {
AggregatedDictionaryState state = ServiceManager.getService(project, AggregatedDictionaryState.class);
state.setProject(project);
state.loadState();
@@ -43,7 +43,7 @@ public class StateLoader implements Loader {
final Set<String> storedWords = dictionary.getWords();
if (storedWords!=null){
for (String word : storedWords) {
processor.process(word);
consumer.consume(word);
}
}
}
@@ -0,0 +1,44 @@
/*
* Copyright 2000-2009 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.spellchecker.util;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.Consumer;
import com.intellij.util.Processor;
import java.io.File;
@SuppressWarnings({"UtilityClassWithoutPrivateConstructor"})
public class SPFileUtil {
public static void processFilesRecursively(final String rootPath, final Consumer<String> consumer){
final File rootFile = new File(rootPath);
if (rootFile.exists() && rootFile.isDirectory()){
FileUtil.processFilesRecursively(rootFile, new Processor<File>() {
public boolean process(final File file) {
if (!file.isDirectory()){
final String path = file.getPath();
if (path.endsWith(".dic")){
consumer.consume(path);
}
}
return true;
}
});
}
}
}
@@ -25,3 +25,8 @@ no.suggestions=<no suggestion>
process.code=Process code
process.literals=Process literals
process.comments=Process comments
link.to.settings=Manage Dictionaries
link.to.inspection.settings=Manage spelling inspection settings
exact.rename.to=Typo: Rename to ''{0}''
add.directory.title=User Dictionary Path
directory.is.already.included=Directory is already included
@@ -23,19 +23,31 @@ import java.util.List;
public class SuggestionTest extends JavaCodeInsightFixtureTestCase {
private SpellCheckerManager spManager;
private SpellCheckerManager getManager(){
if (spManager==null){
spManager = SpellCheckerManager.getInstance(getProject());
}
assert spManager!=null;
return spManager;
}
public void testSuggestions(){
SpellCheckerManager manager = SpellCheckerManager.getInstance(getProject());
assert manager!=null;
List<String> result = manager.getSuggestions("upgade");
assertEquals(result.get(0),"upgrade");
List<String> result = getManager().getSuggestions("upgade");
assertEquals("upgrade",result.get(0));
}
public void testFirstLetterUppercaseSuggestions(){
List<String> result = getManager().getSuggestions("Upgade");
assertEquals("Upgrade",result.get(0));
}
public void testCamelCaseSuggestions(){
SpellCheckerManager manager = SpellCheckerManager.getInstance(getProject());
assert manager!=null;
List<String> result = manager.getSuggestions("Upgade");
assertEquals(result.get(0),"Upgrade");
List<String> result = manager.getSuggestions("TestUpgade");
assertEquals("TestUpgrade",result.get(0));
}
}