resource bundle editor: ignore locales for incomplete properties by alt+enter + added fake inspection

This commit is contained in:
Dmitry Batkovich
2015-10-09 13:09:45 +03:00
parent 99e5213b3f
commit 5830893cf8
20 changed files with 954 additions and 612 deletions
@@ -53,7 +53,7 @@ import java.util.*;
/**
* @author cdr
*/
class IntentionListStep implements ListPopupStep<IntentionActionWithTextCaching>, SpeedSearchFilter<IntentionActionWithTextCaching> {
public class IntentionListStep implements ListPopupStep<IntentionActionWithTextCaching>, SpeedSearchFilter<IntentionActionWithTextCaching> {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.intention.impl.IntentionListStep");
private final Set<IntentionActionWithTextCaching> myCachedIntentions =
@@ -65,6 +65,7 @@ class IntentionListStep implements ListPopupStep<IntentionActionWithTextCaching>
private final IntentionManagerSettings mySettings;
@Nullable
private final IntentionHintComponent myIntentionHintComponent;
@Nullable
private final Editor myEditor;
private final PsiFile myFile;
private final Project myProject;
@@ -81,9 +82,9 @@ class IntentionListStep implements ListPopupStep<IntentionActionWithTextCaching>
};
private Runnable myFinalRunnable;
IntentionListStep(@Nullable IntentionHintComponent intentionHintComponent,
public IntentionListStep(@Nullable IntentionHintComponent intentionHintComponent,
@NotNull ShowIntentionsPass.IntentionsInfo intentions,
@NotNull Editor editor,
@Nullable Editor editor,
@NotNull PsiFile file,
@NotNull Project project) {
this(intentionHintComponent, editor, file, project);
@@ -91,7 +92,7 @@ class IntentionListStep implements ListPopupStep<IntentionActionWithTextCaching>
}
IntentionListStep(@Nullable IntentionHintComponent intentionHintComponent,
@NotNull Editor editor,
@Nullable Editor editor,
@NotNull PsiFile file,
@NotNull Project project) {
myIntentionHintComponent = intentionHintComponent;
@@ -113,7 +114,7 @@ class IntentionListStep implements ListPopupStep<IntentionActionWithTextCaching>
private boolean wrapActionsTo(@NotNull List<HighlightInfo.IntentionActionDescriptor> newDescriptors,
@NotNull Set<IntentionActionWithTextCaching> cachedActions,
boolean callUpdate) {
final int caretOffset = myEditor.getCaretModel().getOffset();
final int caretOffset = myEditor == null ? 0 : myEditor.getCaretModel().getOffset();
final int fileOffset = caretOffset > 0 && caretOffset == myFile.getTextLength() ? caretOffset - 1 : caretOffset;
PsiElement element;
final PsiElement hostElement;
@@ -121,7 +122,7 @@ class IntentionListStep implements ListPopupStep<IntentionActionWithTextCaching>
hostElement = element = myFile;
}
else if (PsiDocumentManager.getInstance(myProject).isUncommited(myEditor.getDocument())) {
else if (myEditor != null && PsiDocumentManager.getInstance(myProject).isUncommited(myEditor.getDocument())) {
//???
FileViewProvider viewProvider = myFile.getViewProvider();
hostElement = element = viewProvider.findElementAt(fileOffset, viewProvider.getBaseLanguage());
@@ -138,14 +139,14 @@ class IntentionListStep implements ListPopupStep<IntentionActionWithTextCaching>
}
else {
injectedFile = element.getContainingFile();
injectedEditor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(myEditor, injectedFile);
injectedEditor = myEditor == null ? null : InjectedLanguageUtil.getInjectedEditorForInjectedFile(myEditor, injectedFile);
}
boolean changed = false;
for (Iterator<IntentionActionWithTextCaching> iterator = cachedActions.iterator(); iterator.hasNext();) {
IntentionActionWithTextCaching cachedAction = iterator.next();
IntentionAction action = cachedAction.getAction();
if (!ShowIntentionActionsHandler.availableFor(myFile, myEditor, action)
if (myEditor != null && !ShowIntentionActionsHandler.availableFor(myFile, myEditor, action)
&& (hostElement == element || element != null && !ShowIntentionActionsHandler.availableFor(injectedFile, injectedEditor, action))) {
iterator.remove();
changed = true;
@@ -155,12 +156,12 @@ class IntentionListStep implements ListPopupStep<IntentionActionWithTextCaching>
Set<IntentionActionWithTextCaching> wrappedNew = new THashSet<IntentionActionWithTextCaching>(newDescriptors.size(), ACTION_TEXT_AND_CLASS_EQUALS);
for (HighlightInfo.IntentionActionDescriptor descriptor : newDescriptors) {
final IntentionAction action = descriptor.getAction();
if (element != null && element != hostElement && (!callUpdate || ShowIntentionActionsHandler.availableFor(injectedFile, injectedEditor, action))) {
if (element != null && element != hostElement && (!callUpdate || myEditor == null || ShowIntentionActionsHandler.availableFor(injectedFile, injectedEditor, action))) {
IntentionActionWithTextCaching cachedAction = wrapAction(descriptor, element, injectedFile, injectedEditor);
wrappedNew.add(cachedAction);
changed |= cachedActions.add(cachedAction);
}
else if (hostElement != null && (!callUpdate || ShowIntentionActionsHandler.availableFor(myFile, myEditor, action))) {
else if (hostElement != null && (!callUpdate || myEditor == null || ShowIntentionActionsHandler.availableFor(myFile, myEditor, action))) {
IntentionActionWithTextCaching cachedAction = wrapAction(descriptor, hostElement, myFile, myEditor);
wrappedNew.add(cachedAction);
changed |= cachedActions.add(cachedAction);
@@ -181,7 +182,7 @@ class IntentionListStep implements ListPopupStep<IntentionActionWithTextCaching>
IntentionActionWithTextCaching wrapAction(@NotNull HighlightInfo.IntentionActionDescriptor descriptor,
@NotNull PsiElement element,
@NotNull PsiFile containingFile,
@NotNull Editor containingEditor) {
@Nullable Editor containingEditor) {
IntentionActionWithTextCaching cachedAction = new IntentionActionWithTextCaching(descriptor);
final List<IntentionAction> options = descriptor.getOptions(element, containingEditor);
if (options == null) return cachedAction;
@@ -252,12 +253,15 @@ class IntentionListStep implements ListPopupStep<IntentionActionWithTextCaching>
}
PsiDocumentManager.getInstance(myProject).commitAllDocuments();
final PsiFile file = PsiUtilBase.getPsiFileInEditor(myEditor, myProject);
if (file == null) {
return;
PsiFile file = null;
if (myEditor != null) {
file = PsiUtilBase.getPsiFileInEditor(myEditor, myProject);
if (file == null) {
return;
}
}
ShowIntentionActionsHandler.chooseActionAndInvoke(file, myEditor, cachedAction.getAction(), cachedAction.getText());
ShowIntentionActionsHandler.chooseActionAndInvoke(file, myEditor, cachedAction.getAction(), cachedAction.getText(), myProject);
}
});
}
@@ -166,31 +166,39 @@ public class ShowIntentionActionsHandler implements CodeInsightActionHandler {
@NotNull final Editor hostEditor,
@NotNull final IntentionAction action,
@NotNull String text) {
if (!hostFile.isValid()) return false;
final Project project = hostFile.getProject();
return chooseActionAndInvoke(hostFile, hostEditor, action, text, project);
}
public static boolean chooseActionAndInvoke(@Nullable PsiFile hostFile,
@Nullable final Editor hostEditor,
@NotNull final IntentionAction action,
@NotNull String text,
@NotNull final Project project) {
FeatureUsageTracker.getInstance().triggerFeatureUsed("codeassists.quickFix");
((FeatureUsageTrackerImpl)FeatureUsageTracker.getInstance()).getFixesStats().registerInvocation();
Pair<PsiFile, Editor> pair = chooseBetweenHostAndInjected(hostFile, hostEditor, new PairProcessor<PsiFile, Editor>() {
final Pair<PsiFile, Editor> pair = hostEditor != null && hostFile != null
? chooseBetweenHostAndInjected(hostFile, hostEditor, new PairProcessor<PsiFile, Editor>() {
@Override
public boolean process(PsiFile psiFile, Editor editor) {
return availableFor(psiFile, editor, action);
}
});
}) : Pair.<PsiFile, Editor>create(null, null);
if (pair == null) return false;
final Editor editorToApply = pair.second;
final PsiFile fileToApply = pair.first;
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
action.invoke(project, editorToApply, fileToApply);
action.invoke(project, pair.second, pair.first);
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
DaemonCodeAnalyzer.getInstance(project).updateVisibleHighlighters(hostEditor);
if (hostEditor != null) {
DaemonCodeAnalyzer.getInstance(project).updateVisibleHighlighters(hostEditor);
}
}
};
@@ -28,6 +28,7 @@ import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Iconable;
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
import com.intellij.psi.PsiFile;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -67,18 +68,27 @@ public class DisableInspectionToolAction extends IntentionAndQuickFixAction impl
}
@Override
public void applyFix(@NotNull Project project, PsiFile file, @Nullable Editor editor) {
public void applyFix(@NotNull Project project, final PsiFile file, @Nullable Editor editor) {
modifyAndCommitProjectProfile(new Consumer<ModifiableModel>() {
@Override
public void consume(ModifiableModel modifiableModel) {
modifiableModel.disableTool(myToolId, file);
}
}, project);
DaemonCodeAnalyzer.getInstance(project).restart();
}
public static void modifyAndCommitProjectProfile(Consumer<ModifiableModel> action, Project project) {
InspectionProjectProfileManager profileManager = InspectionProjectProfileManager.getInstance(project);
InspectionProfile inspectionProfile = profileManager.getInspectionProfile();
ModifiableModel model = inspectionProfile.getModifiableModel();
model.disableTool(myToolId, file);
action.consume(model);
try {
model.commit();
}
catch (IOException e) {
Messages.showErrorDialog(project, e.getMessage(), CommonBundle.getErrorTitle());
}
DaemonCodeAnalyzer.getInstance(project).restart();
}
@Override
@@ -78,4 +78,7 @@ create.resource.bundle.dialog.add.locales.validator.title=Add Locales
add.property.files.to.resource.bundle.dialog.action.title=Add Property Files to Resource Bundle
resource.bundle.editor.settings.action.title=Resource bundle editor settings
resource.bundle.editor.settings.action.title=Resource bundle editor settings
incomplete.property.inspection.display.name=Property is incomplete
incomplete.property.quick.fix.name=Ignore untranslated locales
incomplete.property.inspection.description=Property ''{0}'' is incomplete
@@ -1,160 +0,0 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang.properties.editor;
import com.intellij.lang.properties.PropertiesUtil;
import com.intellij.lang.properties.ResourceBundle;
import com.intellij.lang.properties.psi.PropertiesFile;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.components.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashSet;
import com.intellij.util.xmlb.annotations.AbstractCollection;
import com.intellij.util.xmlb.annotations.Property;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* @author Dmitry Batkovich
*/
@State(
name = "IgnoredPropertiesFilesSuffixesManager",
storages = {
@Storage(file = StoragePathMacros.PROJECT_FILE),
@Storage(file = StoragePathMacros.PROJECT_CONFIG_DIR + "/resourceBundles.xml", scheme = StorageScheme.DIRECTORY_BASED)
})
public class IgnoredPropertiesFilesSuffixesManager implements PersistentStateComponent<IgnoredPropertiesFilesSuffixesManager.IgnoredPropertiesFilesSuffixesState>, Disposable {
private IgnoredPropertiesFilesSuffixesState myState = new IgnoredPropertiesFilesSuffixesState();
private final List<SuffixesListener> myListeners = new ArrayList<SuffixesListener>();
public IgnoredPropertiesFilesSuffixesManager(final Project project) {
Disposer.register(project, this);
}
public static IgnoredPropertiesFilesSuffixesManager getInstance(final Project project) {
return ServiceManager.getService(project, IgnoredPropertiesFilesSuffixesManager.class);
}
public void addListener(final SuffixesListener listener) {
myListeners.add(listener);
}
public void removeListener(final SuffixesListener listener) {
myListeners.remove(listener);
}
public boolean isPropertyComplete(final ResourceBundle resourceBundle, final String key) {
List<PropertiesFile> propertiesFiles = resourceBundle.getPropertiesFiles();
for (PropertiesFile propertiesFile : propertiesFiles) {
if (propertiesFile.findPropertyByKey(key) == null && !myState.getIgnoredSuffixes().contains(PropertiesUtil.getSuffix(propertiesFile))) {
return false;
}
}
return true;
}
public Set<String> getIgnoredSuffixes() {
return myState.getIgnoredSuffixes();
}
public List<PropertiesFile> getPropertiesFilesWithoutTranslation(final ResourceBundle resourceBundle, final Set<String> keys) {
final PropertiesFile defaultPropertiesFile = resourceBundle.getDefaultPropertiesFile();
return ContainerUtil.filter(resourceBundle.getPropertiesFiles(), new Condition<PropertiesFile>() {
@Override
public boolean value(PropertiesFile propertiesFile) {
if (defaultPropertiesFile.equals(propertiesFile)) {
return false;
}
for (String key : keys) {
if (propertiesFile.findPropertyByKey(key) == null && !myState.getIgnoredSuffixes().contains(PropertiesUtil.getSuffix(propertiesFile))) {
return true;
}
}
return false;
}
});
}
public void addSuffixes(Collection<String> suffixes) {
final Set<String> oldSuffixes = new HashSet<String>(myState.getIgnoredSuffixes());
myState.addSuffixes(suffixes);
final Set<String> newSuffixes = myState.getIgnoredSuffixes();
if (!oldSuffixes.equals(newSuffixes)) {
for (SuffixesListener listener : myListeners) {
listener.suffixesChanged();
}
}
}
public void setSuffixes(Collection<String> suffixes) {
final Set<String> oldSuffixes = myState.getIgnoredSuffixes();
myState.setSuffixes(suffixes);
if (!oldSuffixes.equals(suffixes)) {
for (SuffixesListener listener : myListeners) {
listener.suffixesChanged();
}
}
}
@Nullable
@Override
public IgnoredPropertiesFilesSuffixesState getState() {
return myState.isEmpty() ? null : myState;
}
@Override
public void loadState(IgnoredPropertiesFilesSuffixesState state) {
myState = state;
}
@Override
public void dispose() {
if (!myListeners.isEmpty()) {
myListeners.clear();
}
}
public static class IgnoredPropertiesFilesSuffixesState {
@Property(surroundWithTag = false)
@AbstractCollection(elementTag = "ignored-suffix", surroundWithTag = false)
public Set<String> myIgnoredSuffixes = new HashSet<String>();
public void addSuffixes(Collection<String> suffixes) {
myIgnoredSuffixes.addAll(suffixes);
}
public void setSuffixes(Collection<String> suffixes) {
myIgnoredSuffixes = new HashSet<String>(suffixes);
}
public Set<String> getIgnoredSuffixes() {
return myIgnoredSuffixes;
}
public boolean isEmpty() {
return myIgnoredSuffixes.isEmpty();
}
}
public interface SuffixesListener {
void suffixesChanged();
}
}
@@ -22,13 +22,15 @@ package com.intellij.lang.properties.editor;
import com.intellij.ide.structureView.StructureViewTreeElement;
import com.intellij.lang.properties.*;
import com.intellij.lang.properties.ResourceBundle;
import com.intellij.navigation.ColoredItemPresentation;
import com.intellij.lang.properties.editor.inspections.ResourceBundleEditorInspectionPass;
import com.intellij.lang.properties.editor.inspections.ResourceBundleEditorProblemDescriptor;
import com.intellij.lang.properties.editor.inspections.ResourceBundleEditorRenderer;
import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.psi.PsiFile;
import com.intellij.ui.JBColor;
import com.intellij.util.PlatformIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -37,32 +39,23 @@ import javax.swing.*;
import java.awt.*;
public class ResourceBundlePropertyStructureViewElement implements StructureViewTreeElement, ResourceBundleEditorViewElement {
private final ResourceBundle myResourceBundle;
@NotNull private final PropertiesAnchorizer.PropertyAnchor myAnchor;
private String myPresentableName;
private static final TextAttributesKey INCOMPLETE_PROPERTY_KEY;
private static final TextAttributesKey INCOMPLETE_GROUP_KEY;
private static final TextAttributesKey GROUP_KEY;
public static final String PROPERTY_GROUP_KEY_TEXT = "<property>";
static {
TextAttributes incompleteKeyTextAttributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(PropertiesHighlighter.PROPERTY_KEY).clone();
incompleteKeyTextAttributes.setForegroundColor(JBColor.RED);
INCOMPLETE_PROPERTY_KEY = TextAttributesKey.createTextAttributesKey("INCOMPLETE_PROPERTY_KEY", incompleteKeyTextAttributes);
private final @NotNull PropertiesAnchorizer.PropertyAnchor myAnchor;
private String myPresentableName;
static {
TextAttributes groupKeyTextAttributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(PropertiesHighlighter.PROPERTY_KEY).clone();
groupKeyTextAttributes.setFontType(Font.ITALIC);
GROUP_KEY = TextAttributesKey.createTextAttributesKey("GROUP_KEY", groupKeyTextAttributes);
final TextAttributes incompleteGroupKeyTextAttribute = groupKeyTextAttributes.clone();
incompleteGroupKeyTextAttribute.setForegroundColor(JBColor.RED);
INCOMPLETE_GROUP_KEY = TextAttributesKey.createTextAttributesKey("INCOMPLETE_GROUP_KEY", incompleteGroupKeyTextAttribute);
}
private ResourceBundleEditorInspectionPass.InspectionPassInfo myInspectionPassInfo;
public ResourceBundlePropertyStructureViewElement(final ResourceBundle resourceBundle, final @NotNull PropertiesAnchorizer.PropertyAnchor anchor) {
myResourceBundle = resourceBundle;
myAnchor = anchor;
}
@@ -97,10 +90,16 @@ public class ResourceBundlePropertyStructureViewElement implements StructureView
return EMPTY_ARRAY;
}
@NotNull
public ResourceBundleEditorProblemDescriptor[] getProblemDescriptors() {
return myInspectionPassInfo.getDescriptors();
}
@Override
@NotNull
public ItemPresentation getPresentation() {
return new ColoredItemPresentation() {
return new ResourceBundleEditorRenderer.TextAttributesPresentation() {
@Override
public String getPresentableText() {
return myPresentableName == null ? getProperty().getName() : myPresentableName.isEmpty() ? PROPERTY_GROUP_KEY_TEXT : myPresentableName;
@@ -117,14 +116,15 @@ public class ResourceBundlePropertyStructureViewElement implements StructureView
}
@Override
public TextAttributesKey getTextAttributesKey() {
final IgnoredPropertiesFilesSuffixesManager
ignoredPropertiesFilesSuffixesManager = IgnoredPropertiesFilesSuffixesManager.getInstance(myResourceBundle.getProject());
final boolean isPropertyComplete = ignoredPropertiesFilesSuffixesManager.isPropertyComplete(myResourceBundle, getProperty().getName());
if (myPresentableName != null && myPresentableName.isEmpty()) {
return isPropertyComplete ? GROUP_KEY : INCOMPLETE_GROUP_KEY;
public TextAttributes getTextAttributes(EditorColorsScheme colorsScheme) {
myInspectionPassInfo = ResourceBundleEditorInspectionPass.inspect(getProperty().getKey(), getProperty().getPropertiesFile().getResourceBundle());
final TextAttributesKey baseAttrKey = (myPresentableName != null && myPresentableName.isEmpty()) ? GROUP_KEY : PropertiesHighlighter.PROPERTY_KEY;
final TextAttributes baseAttrs = colorsScheme.getAttributes(baseAttrKey);
TextAttributes highlightingAttributes = myInspectionPassInfo.getTextAttributes(colorsScheme);
if (highlightingAttributes != null) {
return TextAttributes.merge(baseAttrs, highlightingAttributes);
}
return isPropertyComplete ? PropertiesHighlighter.PROPERTY_KEY : INCOMPLETE_PROPERTY_KEY;
return baseAttrs;
}
};
}
@@ -0,0 +1,58 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang.properties.editor.inspections;
import com.intellij.codeInspection.*;
import com.intellij.lang.properties.IProperty;
import com.intellij.lang.properties.ResourceBundle;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* @author Dmitry Batkovich
*/
public abstract class ResourceBundleEditorInspection extends LocalInspectionTool {
@Nullable
public abstract ResourceBundleEditorProblemDescriptor[] checkPropertyGroup(@NotNull List<IProperty> properties,
@NotNull ResourceBundle resourceBundle);
@NotNull
@Override
public final PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
return PsiElementVisitor.EMPTY_VISITOR;
}
@NotNull
@Override
public final PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder,
boolean isOnTheFly,
@NotNull LocalInspectionToolSession session) {
return PsiElementVisitor.EMPTY_VISITOR;
}
@Nullable
@Override
public final ProblemDescriptor[] checkFile(@NotNull PsiFile file,
@NotNull InspectionManager manager,
boolean isOnTheFly) {
return null;
}
}
@@ -0,0 +1,131 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang.properties.editor.inspections;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
import com.intellij.codeInsight.daemon.impl.SeverityRegistrar;
import com.intellij.codeInspection.ProblemDescriptorUtil;
import com.intellij.codeInspection.QuickFix;
import com.intellij.codeInspection.ex.InspectionProfileWrapper;
import com.intellij.codeInspection.ex.InspectionToolWrapper;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.lang.properties.IProperty;
import com.intellij.lang.properties.ResourceBundle;
import com.intellij.lang.properties.psi.PropertiesFile;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.profile.codeInspection.InspectionProjectProfileManagerImpl;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.Function;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* @author Dmitry Batkovich
*/
public class ResourceBundleEditorInspectionPass {
@Nullable
public static InspectionPassInfo inspect(@NotNull final String key, ResourceBundle resourceBundle) {
final List<IProperty> properties =
ContainerUtil.mapNotNull(resourceBundle.getPropertiesFiles(), new Function<PropertiesFile, IProperty>() {
@Override
public IProperty fun(PropertiesFile propertiesFile) {
return propertiesFile.findPropertyByKey(key);
}
});
if (properties.isEmpty()) {
return null;
}
final IProperty property = properties.get(0);
final PsiElement representativeElement = property.getPsiElement();
final PsiFile representativeFile = representativeElement.getContainingFile();
final Project project = representativeElement.getProject();
InspectionProfileWrapper profileToUse = InspectionProjectProfileManagerImpl.getInstanceImpl(project).getProfileWrapper();
final PsiFile containingFile = representativeFile.getContainingFile();
final InspectionToolWrapper[] propertiesTools = profileToUse.getInspectionTools(containingFile);
List<ResourceBundleEditorProblemDescriptor> allDescriptors = new SmartList<ResourceBundleEditorProblemDescriptor>();
SortedSet<HighlightInfoType> highlightTypes = new TreeSet<HighlightInfoType>(new Comparator<HighlightInfoType>() {
@Override
public int compare(HighlightInfoType o1, HighlightInfoType o2) {
final HighlightSeverity s1 = o1.getSeverity(null);
final HighlightSeverity s2 = o2.getSeverity(null);
return Comparing.compare(s1, s2);
}
});
for (InspectionToolWrapper tool : propertiesTools) {
final HighlightDisplayKey toolKey;
if (tool.getTool() instanceof ResourceBundleEditorInspection &&
profileToUse.isToolEnabled(toolKey = HighlightDisplayKey.find(tool.getShortName()), containingFile)) {
final ResourceBundleEditorInspection inspection = (ResourceBundleEditorInspection)tool.getTool();
final ResourceBundleEditorProblemDescriptor[] descriptors = inspection.checkPropertyGroup(properties, resourceBundle);
if (descriptors != null) {
for (ResourceBundleEditorProblemDescriptor descriptor : descriptors) {
final QuickFix[] currentFixes = descriptor.getFixes();
if (currentFixes != null && currentFixes.length != 0) {
Collections.addAll(allDescriptors, descriptor);
}
HighlightSeverity severity = profileToUse.getInspectionProfile().getErrorLevel(toolKey, containingFile).getSeverity();
final HighlightInfoType infoType =
ProblemDescriptorUtil.highlightTypeFromDescriptor(descriptor, severity, SeverityRegistrar.getSeverityRegistrar(project));
highlightTypes.add(infoType);
}
}
}
}
return new InspectionPassInfo(allDescriptors.toArray(new ResourceBundleEditorProblemDescriptor[allDescriptors.size()]), highlightTypes);
}
public static class InspectionPassInfo {
private final ResourceBundleEditorProblemDescriptor[] myDescriptors;
private final SortedSet<HighlightInfoType> myHighlightTypes;
public InspectionPassInfo(ResourceBundleEditorProblemDescriptor[] descriptors, SortedSet<HighlightInfoType> types) {
myDescriptors = descriptors;
myHighlightTypes = types;
}
public ResourceBundleEditorProblemDescriptor[] getDescriptors() {
return myDescriptors;
}
@Nullable
public TextAttributes getTextAttributes(EditorColorsScheme scheme) {
TextAttributes mixedAttributes = null;
for (HighlightInfoType type : myHighlightTypes) {
final TextAttributes current = scheme.getAttributes(type.getAttributesKey());
if (mixedAttributes == null) {
mixedAttributes = current;
} else {
mixedAttributes = TextAttributes.merge(mixedAttributes, current);
}
}
return mixedAttributes;
}
}
}
@@ -0,0 +1,109 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang.properties.editor.inspections;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.QuickFix;
import com.intellij.lang.annotation.ProblemGroup;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Dmitry Batkovich
*/
public class ResourceBundleEditorProblemDescriptor implements ProblemDescriptor {
private final ProblemHighlightType myHighlightType;
private final String myDescriptionTemplate;
private final QuickFix[] myFixes;
public ResourceBundleEditorProblemDescriptor(final ProblemHighlightType type, String template, QuickFix<ResourceBundleEditorProblemDescriptor>... fixes) {
myHighlightType = type;
myDescriptionTemplate = template;
myFixes = fixes;
}
@NotNull
public ProblemHighlightType getHighlightType() {
return myHighlightType;
}
@NotNull
@Override
public String getDescriptionTemplate() {
return myDescriptionTemplate;
}
@Nullable
@Override
public QuickFix[] getFixes() {
return myFixes;
}
@Override
public PsiElement getPsiElement() {
throw new UnsupportedOperationException();
}
@Override
public PsiElement getStartElement() {
throw new UnsupportedOperationException();
}
@Override
public PsiElement getEndElement() {
throw new UnsupportedOperationException();
}
@Override
public TextRange getTextRangeInElement() {
throw new UnsupportedOperationException();
}
@Override
public int getLineNumber() {
throw new UnsupportedOperationException();
}
@Override
public boolean isAfterEndOfLine() {
throw new UnsupportedOperationException();
}
@Override
public void setTextAttributes(TextAttributesKey key) {
throw new UnsupportedOperationException();
}
@Nullable
@Override
public ProblemGroup getProblemGroup() {
throw new UnsupportedOperationException();
}
@Override
public void setProblemGroup(@Nullable ProblemGroup problemGroup) {
throw new UnsupportedOperationException();
}
@Override
public boolean showTooltip() {
throw new UnsupportedOperationException();
}
}
@@ -0,0 +1,75 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang.properties.editor.inspections;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.ide.util.treeView.NodeRenderer;
import com.intellij.ide.util.treeView.smartTree.TreeElement;
import com.intellij.ide.util.treeView.smartTree.TreeElementWrapper;
import com.intellij.lang.properties.editor.ResourceBundlePropertyStructureViewElement;
import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.ui.SimpleTextAttributes;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.*;
/**
* @author Dmitry Batkovich
*/
public class ResourceBundleEditorRenderer extends NodeRenderer {
@Override
public void customizeCellRenderer(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
if (customize(value)) {
return;
}
super.customizeCellRenderer(tree, value, selected, expanded, leaf, row, hasFocus);
}
private boolean customize(Object value) {
final Object userObject = ((DefaultMutableTreeNode)value).getUserObject();
if (!(userObject instanceof TreeElementWrapper)) {
return false;
}
final TreeElement treeElement = ((TreeElementWrapper)userObject).getValue();
if (treeElement == null) {
return false;
}
final ItemPresentation presentation = treeElement.getPresentation();
if (presentation instanceof TextAttributesPresentation) {
final TextAttributesPresentation textAttributesPresentation = (TextAttributesPresentation)presentation;
final String text = textAttributesPresentation.getPresentableText();
if (text != null) {
final SimpleTextAttributes attr =
SimpleTextAttributes.fromTextAttributes(textAttributesPresentation.getTextAttributes(getColorsScheme()));
append(text, new SimpleTextAttributes(attr.getBgColor(), attr.getFgColor(), attr.getWaveColor(),
attr.getStyle() | SimpleTextAttributes.STYLE_OPAQUE));
return true;
}
}
return false;
}
public interface TextAttributesPresentation extends ItemPresentation {
TextAttributes getTextAttributes(EditorColorsScheme colorsScheme);
}
}
+8 -7
View File
@@ -86,6 +86,10 @@
key="wrong.property.key.value.delimiter.inspection.display.name" groupKey="properties.files.inspection.group.display.name"
enabledByDefault="true" level="WEAK WARNING" cleanupTool="true"
implementationClass="com.intellij.codeInspection.WrongPropertyKeyValueDelimiterInspection"/>
<localInspection language="Properties" shortName="IncompleteProperty" bundle="messages.PropertiesBundle"
key="incomplete.property.inspection.display.name" groupKey="properties.files.inspection.group.display.name"
enabledByDefault="true" level="ERROR" cleanupTool="false"
implementationClass="com.intellij.lang.properties.editor.inspections.incomplete.IncompletePropertyInspection"/>
<idIndexer filetype="Properties" implementationClass="com.intellij.psi.impl.cache.impl.idCache.PropertiesIdIndexer"/>
<todoIndexer filetype="Properties" implementationClass="com.intellij.psi.impl.cache.impl.idCache.PropertiesTodoIndexer"/>
@@ -107,13 +111,6 @@
<codeStyleSettingsProvider implementation="com.intellij.lang.properties.psi.codeStyle.PropertiesCodeStyleSettingsProvider"/>
<projectConfigurable groupId="tools"
groupWeight="10"
provider="com.intellij.lang.properties.ResourceBundleEditorConfigurable$Provider"
id="resource.bundle.editor.highlighting.settings"
displayName="Resource Bundle Editor"/>
<projectService serviceImplementation="com.intellij.lang.properties.editor.IgnoredPropertiesFilesSuffixesManager"/>
<internalFileTemplate name="XML Properties File.xml"/>
<refactoring.copyHandler implementation="com.intellij.lang.properties.editor.PropertiesCopyHandler"/>
</extensions>
@@ -156,5 +153,9 @@
<action id="CreateResourceBundle" class="com.intellij.lang.properties.create.CreateResourceBundleAction">
<add-to-group group-id="NewGroup" anchor="after" relative-to-action="NewFromTemplate"/>
</action>
<action id="ResourceBundleEditorShowIntentions"
class="com.intellij.lang.properties.editor.ResourceBundleEditorShowQuickFixesAction"
use-shortcut-of="ShowIntentionActions"/>
</actions>
</idea-plugin>
@@ -1,149 +0,0 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang.properties;
import com.intellij.lang.properties.editor.IgnoredPropertiesFilesSuffixesManager;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.options.BaseConfigurable;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurableProvider;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.*;
import com.intellij.ui.components.JBList;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
/**
* @author Dmitry Batkovich
*/
public class ResourceBundleEditorConfigurable extends BaseConfigurable {
private final JPanel myPanel;
private final CollectionListModel<String> mySuffixesModel;
private final IgnoredPropertiesFilesSuffixesManager mySuffixesManager;
public ResourceBundleEditorConfigurable(@NotNull Project project) {
mySuffixesManager = IgnoredPropertiesFilesSuffixesManager.getInstance(project);
final JBList list = new JBList();
final List<String> suffixes = new ArrayList<String>(mySuffixesManager.getIgnoredSuffixes());
mySuffixesModel = new CollectionListModel<String>(suffixes);
mySuffixesModel.sort(String.CASE_INSENSITIVE_ORDER);
list.setModel(mySuffixesModel);
myPanel = ToolbarDecorator.createDecorator(list).disableUpDownActions().setAddAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
final String result = Messages.showInputDialog(CommonDataKeys.PROJECT.getData(button.getDataContext()),
"Suffixes to ignore (use comma to separate suffixes):",
"Add Ignored Suffixes", null);
if (result != null) {
final List<String> suffixes = StringUtil.split(result, ",");
for (String suffix : suffixes) {
if (mySuffixesModel.getElementIndex(suffix) == -1) {
mySuffixesModel.add(suffix);
}
}
updateModifiedStatus();
mySuffixesModel.sort(String.CASE_INSENSITIVE_ORDER);
}
}
}).setRemoveAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
for (Object toDelete : list.getSelectedValues()) {
mySuffixesModel.remove((String)toDelete);
}
updateModifiedStatus();
}
}).createPanel();
list.setCellRenderer(new ColoredListCellRenderer<String>() {
@Override
protected void customizeCellRenderer(JList list, String suffix, int index, boolean selected, boolean hasFocus) {
append(suffix);
final Locale locale = PropertiesUtil.getLocale("_" + suffix + ".properties");
if (locale != PropertiesUtil.DEFAULT_LOCALE && PropertiesUtil.hasDefaultLanguage(locale)) {
append(" ");
append(PropertiesUtil.getPresentableLocale(locale), SimpleTextAttributes.GRAY_ATTRIBUTES);
}
}
});
myPanel.setBorder(IdeBorderFactory.createTitledBorder("Ignored properties file suffixes:"));
}
@Nls
@Override
public String getDisplayName() {
return "Resource Bundle Editor";
}
@Nullable
@Override
public String getHelpTopic() {
return null;
}
@Nullable
@Override
public JComponent createComponent() {
return myPanel;
}
@Override
public void apply() throws ConfigurationException {
mySuffixesManager.setSuffixes(mySuffixesModel.getItems());
setModified(false);
}
@Override
public void reset() {
mySuffixesModel.removeAll();
for (String suffix : mySuffixesManager.getIgnoredSuffixes()) {
mySuffixesModel.add(suffix);
}
mySuffixesModel.sort(String.CASE_INSENSITIVE_ORDER);
setModified(false);
}
@Override
public void disposeUIResources() {
}
private void updateModifiedStatus() {
setModified(!ContainerUtil.newHashSet(mySuffixesModel.getItems()).equals(mySuffixesManager.getIgnoredSuffixes()));
}
public static class Provider extends ConfigurableProvider {
private final Project myProject;
public Provider(Project project) {
myProject = project;
}
@Nullable
@Override
public Configurable createConfigurable() {
return new ResourceBundleEditorConfigurable(myProject);
}
}
}
@@ -1,179 +0,0 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang.properties.editor;
import com.intellij.lang.properties.IProperty;
import com.intellij.lang.properties.PropertiesUtil;
import com.intellij.lang.properties.psi.PropertiesFile;
import com.intellij.lang.properties.psi.Property;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.psi.PsiElement;
import com.intellij.ui.CollectionListModel;
import com.intellij.ui.ToolbarDecorator;
import com.intellij.ui.components.JBList;
import com.intellij.util.NotNullFunction;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.util.List;
/**
* @author Dmitry Batkovich
*/
public class IgnoreIncompletePropertyPropertiesFilesAction extends AnAction {
private final static Logger LOG = Logger.getInstance(IgnoreIncompletePropertyPropertiesFilesAction.class);
public IgnoreIncompletePropertyPropertiesFilesAction() {
super("Ignore Properties Files Without Translation");
}
@Override
public void actionPerformed(AnActionEvent e) {
final ResourceBundleEditor resourceBundleEditor = (ResourceBundleEditor)PlatformDataKeys.FILE_EDITOR.getData(e.getDataContext());
LOG.assertTrue(resourceBundleEditor != null);
final Project project = getEventProject(e);
LOG.assertTrue(project != null);
final Set<String> properties = new HashSet<String>();
processSelectedIncompleteProperties(new Processor<IProperty>() {
@Override
public boolean process(IProperty property) {
properties.add(property.getKey());
return true;
}
}, resourceBundleEditor, project);
final IgnoredPropertiesFilesSuffixesManager suffixesManager = IgnoredPropertiesFilesSuffixesManager.getInstance(project);
final List<PropertiesFile> allFilesWithoutTranslation =
suffixesManager.getPropertiesFilesWithoutTranslation(resourceBundleEditor.getResourceBundle(), properties);
if (allFilesWithoutTranslation.isEmpty()) {
return;
}
Collections.sort(allFilesWithoutTranslation, new Comparator<PropertiesFile>() {
@Override
public int compare(PropertiesFile p1, PropertiesFile p2) {
return p1.getName().compareTo(p2.getName());
}
});
final List<PropertiesFile> suffixRepresentatives =
new IgnoredSuffixesDialog(allFilesWithoutTranslation, project).showAndGetSuffixesRepresentatives();
if (suffixRepresentatives == null) {
return;
}
final List<String> suffixesToIgnore = ContainerUtil.map(suffixRepresentatives, new NotNullFunction<PropertiesFile, String>() {
@NotNull
@Override
public String fun(PropertiesFile propertiesFile) {
return PropertiesUtil.getSuffix(propertiesFile);
}
});
if (!suffixesToIgnore.isEmpty()) {
suffixesManager.addSuffixes(suffixesToIgnore);
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
resourceBundleEditor.queueUpdateTree();
}
});
}
}
private static class IgnoredSuffixesDialog extends DialogWrapper {
@NotNull private final List<PropertiesFile> myPropertiesFiles;
private CollectionListModel<PropertiesFile> myModel;
protected IgnoredSuffixesDialog(@NotNull List<PropertiesFile> propertiesFiles, @NotNull Project project) {
super(project);
myPropertiesFiles = propertiesFiles;
setTitle("Suffixes to Ignore:");
init();
}
@SuppressWarnings("unchecked")
@Nullable
@Override
protected JComponent createCenterPanel() {
final JBList list = new JBList();
myModel = new CollectionListModel<PropertiesFile>(myPropertiesFiles);
list.setModel(myModel);
list.setCellRenderer(new DefaultListCellRenderer() {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
final JLabel label = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
label.setText(PropertiesUtil.getSuffix((PropertiesFile)value));
return label;
}
});
return ToolbarDecorator.createDecorator(list).disableUpDownActions().disableAddAction().createPanel();
}
@Nullable
public List<PropertiesFile> showAndGetSuffixesRepresentatives() {
return showAndGet() ? myModel.getItems() : null;
}
}
@Override
public void update(AnActionEvent e) {
final FileEditor fileEditor = PlatformDataKeys.FILE_EDITOR.getData(e.getDataContext());
if (fileEditor instanceof ResourceBundleEditor) {
ResourceBundleEditor resourceBundleEditor = (ResourceBundleEditor)fileEditor;
final Project project = getEventProject(e);
if (project != null) {
if (!processSelectedIncompleteProperties(new Processor<IProperty>() {
@Override
public boolean process(IProperty property) {
return false;
}
}, resourceBundleEditor, project)) {
e.getPresentation().setEnabledAndVisible(true);
return;
}
}
}
e.getPresentation().setEnabledAndVisible(false);
}
private static boolean processSelectedIncompleteProperties(final @NotNull Processor<IProperty> processor,
final @NotNull ResourceBundleEditor resourceBundleEditor,
final @NotNull Project project) {
final IgnoredPropertiesFilesSuffixesManager suffixesManager = IgnoredPropertiesFilesSuffixesManager.getInstance(project);
for (ResourceBundleEditorViewElement element : resourceBundleEditor.getSelectedElements()) {
final IProperty[] properties = element.getProperties();
if (properties != null) {
for (IProperty property : properties) {
if (!suffixesManager.isPropertyComplete(resourceBundleEditor.getResourceBundle(), property.getKey()) && !processor.process(property)) {
return false;
}
}
}
}
return true;
}
}
@@ -34,6 +34,7 @@ import com.intellij.lang.properties.IProperty;
import com.intellij.lang.properties.PropertiesImplUtil;
import com.intellij.lang.properties.PropertiesUtil;
import com.intellij.lang.properties.ResourceBundle;
import com.intellij.lang.properties.editor.inspections.incomplete.IncompletePropertyInspection;
import com.intellij.lang.properties.psi.PropertiesFile;
import com.intellij.lang.properties.psi.PropertiesResourceBundleUtil;
import com.intellij.openapi.actionSystem.*;
@@ -111,7 +112,6 @@ public class ResourceBundleEditor extends UserDataHolderBase implements Document
private final Set<PropertiesFile> myBackSlashPressed = new THashSet<PropertiesFile>();
private final Alarm mySelectionChangeAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD);
private final PropertiesAnchorizer myPropertiesAnchorizer;
private final IgnoredPropertiesFilesSuffixesManager.SuffixesListener mySuffixesListener;
private JPanel myValuesPanel;
private JPanel myStructureViewPanel;
@@ -201,14 +201,6 @@ public class ResourceBundleEditor extends UserDataHolderBase implements Document
onSelectionChanged(event);
}
});
mySuffixesListener = new IgnoredPropertiesFilesSuffixesManager.SuffixesListener() {
@Override
public void suffixesChanged() {
recreateEditorsPanel();
}
};
IgnoredPropertiesFilesSuffixesManager.getInstance(myProject).addListener(mySuffixesListener);
}
public ResourceBundle getResourceBundle() {
@@ -406,35 +398,6 @@ public class ResourceBundleEditor extends UserDataHolderBase implements Document
myValuesPanel.add(myNoPropertySelectedPanel, NO_PROPERTY_SELECTED);
final List<PropertiesFile> propertiesFiles = myResourceBundle.getPropertiesFiles();
final IgnoredPropertiesFilesSuffixesManager suffixesManager =
IgnoredPropertiesFilesSuffixesManager.getInstance(myResourceBundle.getProject());
if (!suffixesManager.getIgnoredSuffixes().isEmpty()) {
final List<PropertiesFile> initialOrder = new ArrayList<PropertiesFile>(propertiesFiles);
final PropertiesFile defaultPropertiesFile = myResourceBundle.getDefaultPropertiesFile();
Collections.sort(propertiesFiles, new Comparator<PropertiesFile>() {
@Override
public int compare(PropertiesFile p1, PropertiesFile p2) {
if (p1.equals(defaultPropertiesFile)) {
return -1;
}
if (p2.equals(defaultPropertiesFile)) {
return 1;
}
final boolean isIgnored1 = suffixesManager.getIgnoredSuffixes().contains(PropertiesUtil.getSuffix(p1));
final boolean isIgnored2 = suffixesManager.getIgnoredSuffixes().contains(PropertiesUtil.getSuffix(p2));
if (isIgnored1 != isIgnored2) {
if (isIgnored1) {
return 1;
}
else {
return -1;
}
}
return initialOrder.indexOf(p1) - initialOrder.indexOf(p2);
}
});
}
GridBagConstraints gc = new GridBagConstraints(0, 0, 0, 0, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH,
new Insets(5, 5, 5, 5), 0, 0);
@@ -733,12 +696,12 @@ public class ResourceBundleEditor extends UserDataHolderBase implements Document
final String currentKey = selectedProperty.getKey();
final int idx = keysOrder.indexOf(currentKey);
LOG.assertTrue(idx != -1);
final IgnoredPropertiesFilesSuffixesManager
ignoredPropertiesFilesSuffixesManager = IgnoredPropertiesFilesSuffixesManager.getInstance(myProject);
final IncompletePropertyInspection incompletePropertyInspection =
IncompletePropertyInspection.getInstance(myResourceBundle.getDefaultPropertiesFile().getContainingFile());
for (int i = 1; i < keysOrder.size(); i++) {
int trimmedIndex = (i + idx) % keysOrder.size();
final String key = keysOrder.get(trimmedIndex);
if (!ignoredPropertiesFilesSuffixesManager.isPropertyComplete(myResourceBundle, key)) {
if (!incompletePropertyInspection.isPropertyComplete(key, myResourceBundle)) {
selectProperty(key);
return;
}
@@ -894,7 +857,6 @@ public class ResourceBundleEditor extends UserDataHolderBase implements Document
}
}
}
IgnoredPropertiesFilesSuffixesManager.getInstance(myProject).removeListener(mySuffixesListener);
VirtualFileManager.getInstance().removeVirtualFileListener(myVfsListener);
myDisposed = true;
Disposer.dispose(myStructureViewComponent);
@@ -910,10 +872,6 @@ public class ResourceBundleEditor extends UserDataHolderBase implements Document
myEditors.clear();
}
public void queueUpdateTree() {
myStructureViewComponent.getTreeBuilder().queueUpdate();
}
public void setKeepEmptyProperties(boolean keepEmptyProperties) {
myKeepEmptyProperties = keepEmptyProperties;
}
@@ -0,0 +1,135 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang.properties.editor;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.daemon.impl.ShowIntentionsPass;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.impl.IntentionListStep;
import com.intellij.codeInspection.QuickFix;
import com.intellij.icons.AllIcons;
import com.intellij.lang.properties.editor.inspections.ResourceBundleEditorProblemDescriptor;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
import com.intellij.ui.popup.PopupFactoryImpl;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
/**
* @author Dmitry Batkovich
*/
public class ResourceBundleEditorShowQuickFixesAction extends AnAction {
private final static Logger LOG = Logger.getInstance(ResourceBundleEditorShowQuickFixesAction.class);
@Override
public void actionPerformed(AnActionEvent e) {
final ResourceBundleEditor editor = getEditor(e);
LOG.assertTrue(editor != null);
final ResourceBundlePropertyStructureViewElement element = (ResourceBundlePropertyStructureViewElement)editor.getSelectedElementIfOnlyOne();
LOG.assertTrue(element != null);
final PsiFile file = editor.getResourceBundle().getDefaultPropertiesFile().getContainingFile();
final ShowIntentionsPass.IntentionsInfo intentions = new ShowIntentionsPass.IntentionsInfo();
boolean isQuickFixListEmpty = true;
ResourceBundleEditorProblemDescriptor[] descriptors = element.getProblemDescriptors();
for (ResourceBundleEditorProblemDescriptor d : descriptors) {
QuickFix[] fixes = d.getFixes();
if (fixes != null) {
for (int i = 0; i < fixes.length; i++) {
intentions.inspectionFixesToShow.add(new HighlightInfo.IntentionActionDescriptor(new RBEQuickFixWrapper(d, i),
AllIcons.Actions.IntentionBulb));
isQuickFixListEmpty = false;
}
}
}
if (isQuickFixListEmpty) {
return;
}
final Project project = e.getProject();
LOG.assertTrue(project != null);
PopupFactoryImpl
.getInstance()
.createListPopup(new IntentionListStep(null, intentions, null, file, project))
.showInBestPositionFor(e.getDataContext());
}
@Override
public void update(AnActionEvent e) {
final ResourceBundleEditor editor = getEditor(e);
e.getPresentation().setEnabledAndVisible(editor != null &&
editor.getSelectedElementIfOnlyOne() instanceof ResourceBundlePropertyStructureViewElement);
}
private ResourceBundleEditor getEditor(AnActionEvent e) {
final FileEditor editor = PlatformDataKeys.FILE_EDITOR.getData(e.getDataContext());
return editor instanceof ResourceBundleEditor ? (ResourceBundleEditor)editor : null;
}
private static class RBEQuickFixWrapper implements IntentionAction {
private final ResourceBundleEditorProblemDescriptor myDescriptor;
private final int myIndex;
private RBEQuickFixWrapper(ResourceBundleEditorProblemDescriptor descriptor, int index) {
myDescriptor = descriptor;
myIndex = index;
}
@Nls
@NotNull
@Override
public String getText() {
return getFamilyName();
}
@Nls
@NotNull
@Override
public String getFamilyName() {
return getQuickFix().getFamilyName();
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return true;
}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
getQuickFix().applyFix(project, myDescriptor);
}
@Override
public boolean startInWriteAction() {
return false;
}
private QuickFix<ResourceBundleEditorProblemDescriptor> getQuickFix() {
return myDescriptor.getFixes()[myIndex];
}
}
}
@@ -21,9 +21,9 @@ import com.intellij.ide.DeleteProvider;
import com.intellij.ide.actions.ContextHelpAction;
import com.intellij.lang.properties.IProperty;
import com.intellij.lang.properties.ResourceBundle;
import com.intellij.lang.properties.editor.inspections.ResourceBundleEditorRenderer;
import com.intellij.lang.properties.projectView.ResourceBundleDeleteProvider;
import com.intellij.lang.properties.psi.PropertiesFile;
import com.intellij.lang.properties.psi.Property;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.ide.CopyPasteManager;
@@ -64,6 +64,7 @@ public class ResourceBundleStructureViewComponent extends PropertiesGroupingStru
super(resourceBundle.getProject(), editor, new ResourceBundleStructureViewModel(resourceBundle, anchorizer));
myResourceBundle = resourceBundle;
tunePopupActionGroup();
getTree().setCellRenderer(new ResourceBundleEditorRenderer());
}
@Override
@@ -83,7 +84,6 @@ public class ResourceBundleStructureViewComponent extends PropertiesGroupingStru
final DefaultActionGroup propertiesPopupGroup = new DefaultActionGroup();
propertiesPopupGroup.copyFromGroup((DefaultActionGroup)ActionManager.getInstance().getAction(IdeActions.GROUP_STRUCTURE_VIEW_POPUP));
propertiesPopupGroup.add(Separator.getInstance(), Constraints.FIRST);
propertiesPopupGroup.add(new IgnoreIncompletePropertyPropertiesFilesAction(), Constraints.FIRST);
propertiesPopupGroup.add(new NewPropertyAction(true), Constraints.FIRST);
PopupHandler.installPopupHandler(getTree(), propertiesPopupGroup, IdeActions.GROUP_STRUCTURE_VIEW_POPUP, ActionManager.getInstance());
}
@@ -0,0 +1,202 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang.properties.editor.inspections.incomplete;
import com.intellij.codeInspection.InspectionProfile;
import com.intellij.codeInspection.ModifiableModel;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.QuickFix;
import com.intellij.codeInspection.ex.DisableInspectionToolAction;
import com.intellij.lang.properties.*;
import com.intellij.lang.properties.ResourceBundle;
import com.intellij.lang.properties.editor.inspections.ResourceBundleEditorInspection;
import com.intellij.lang.properties.editor.inspections.ResourceBundleEditorProblemDescriptor;
import com.intellij.lang.properties.psi.PropertiesFile;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.SmartPointerManager;
import com.intellij.psi.SmartPsiElementPointer;
import com.intellij.util.Consumer;
import com.intellij.util.Function;
import com.intellij.util.containers.*;
import org.jdom.Element;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.*;
import java.util.List;
/**
* @author Dmitry Batkovich
*/
public class IncompletePropertyInspection extends ResourceBundleEditorInspection {
private static final String SUFFIXES_TAG_NAME = "suffixes";
private static final String TOOL_KEY = "IncompleteProperty";
SortedSet<String> mySuffixes = new TreeSet<String>();
@Nullable
@Override
public JComponent createOptionsPanel() {
return new IncompletePropertyInspectionOptionsPanel(mySuffixes).buildPanel();
}
@Override
public void readSettings(@NotNull Element node) throws InvalidDataException {
mySuffixes.clear();
final Element element = node.getChild(SUFFIXES_TAG_NAME);
if (element != null) {
mySuffixes.addAll(StringUtil.split(element.getText(), ","));
}
}
@Override
public void writeSettings(@NotNull Element node) throws WriteExternalException {
if (!mySuffixes.isEmpty()) {
node.addContent(new Element(SUFFIXES_TAG_NAME).setText(StringUtil.join(mySuffixes, ",")));
}
}
@Nullable
@Override
public ResourceBundleEditorProblemDescriptor[] checkPropertyGroup(@NotNull List<IProperty> properties, @NotNull ResourceBundle resourceBundle) {
return !isPropertyComplete(properties, resourceBundle)
? new ResourceBundleEditorProblemDescriptor[] {new ResourceBundleEditorProblemDescriptor(ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
PropertiesBundle.message("incomplete.property.inspection.description",
properties.get(0).getName()),
new IgnoreLocalesQuickFix(properties.get(0), resourceBundle))}
: null;
}
@NotNull
public static IncompletePropertyInspection getInstance(PsiElement element) {
final InspectionProjectProfileManager profileManager = InspectionProjectProfileManager.getInstance(element.getProject());
InspectionProfile inspectionProfile = profileManager.getInspectionProfile();
return (IncompletePropertyInspection) inspectionProfile.getUnwrappedTool(TOOL_KEY, element);
}
private static class IgnoreLocalesQuickFix implements QuickFix<ResourceBundleEditorProblemDescriptor> {
private final ResourceBundle myResourceBundle;
private final SmartPsiElementPointer<PsiElement> myElementPointer;
public IgnoreLocalesQuickFix(IProperty property, ResourceBundle bundle) {
myElementPointer = SmartPointerManager.getInstance(bundle.getProject()).createSmartPsiElementPointer(property.getPsiElement());
myResourceBundle = bundle;
}
@Nls
@NotNull
@Override
public String getName() {
return getFamilyName();
}
@Nls
@NotNull
@Override
public String getFamilyName() {
return PropertiesBundle.message("incomplete.property.quick.fix.name");
}
@Override
public void applyFix(@NotNull Project project, @NotNull ResourceBundleEditorProblemDescriptor descriptor) {
final PsiElement element = myElementPointer.getElement();
if (element == null) {
return;
}
final IProperty property = PropertiesImplUtil.getProperty(element);
if (property == null) {
return;
}
final IncompletePropertyInspection inspection = getInstance(element);
final List<PropertiesFile> allFilesWithoutTranslation = inspection.getPropertiesFilesWithoutTranslation(myResourceBundle, property.getKey());
if (allFilesWithoutTranslation.isEmpty()) {
return;
}
final TreeSet<String> suffixesToIgnore = new TreeSet<String>(ContainerUtil.map(allFilesWithoutTranslation,
new Function<PropertiesFile, String>() {
@Override
public String fun(PropertiesFile file) {
return PropertiesUtil.getSuffix(file);
}
}));
if (new IncompletePropertyInspectionOptionsPanel(suffixesToIgnore).showDialogAndGet(project)) {
DisableInspectionToolAction.modifyAndCommitProjectProfile(new Consumer<ModifiableModel>() {
@Override
public void consume(ModifiableModel modifiableModel) {
((IncompletePropertyInspection)modifiableModel.getInspectionTool(TOOL_KEY, element).getTool()).addSuffixes(suffixesToIgnore);
}
}, project);
}
}
}
public boolean isPropertyComplete(final String key, final ResourceBundle resourceBundle) {
return isPropertyComplete(ContainerUtil.mapNotNull(resourceBundle.getPropertiesFiles(), new Function<PropertiesFile, IProperty>() {
@Override
public IProperty fun(PropertiesFile file) {
return file.findPropertyByKey(key);
}
}), resourceBundle);
}
private boolean isPropertyComplete(final List<IProperty> properties, final ResourceBundle resourceBundle) {
final Set<PropertiesFile> existed = ContainerUtil.map2Set(properties, new Function<IProperty, PropertiesFile>() {
@Override
public PropertiesFile fun(IProperty property) {
return property.getPropertiesFile();
}
});
for (PropertiesFile file : resourceBundle.getPropertiesFiles()) {
if (!existed.contains(file) && !getIgnoredSuffixes().contains(PropertiesUtil.getSuffix(file))) {
return false;
}
}
return true;
}
public Set<String> getIgnoredSuffixes() {
return mySuffixes;
}
public List<PropertiesFile> getPropertiesFilesWithoutTranslation(final ResourceBundle resourceBundle, final String key) {
final PropertiesFile defaultPropertiesFile = resourceBundle.getDefaultPropertiesFile();
return ContainerUtil.filter(resourceBundle.getPropertiesFiles(), new Condition<PropertiesFile>() {
@Override
public boolean value(PropertiesFile propertiesFile) {
return !defaultPropertiesFile.equals(propertiesFile) &&
propertiesFile.findPropertyByKey(key) == null &&
!getIgnoredSuffixes().contains(PropertiesUtil.getSuffix(propertiesFile));
}
});
}
public void addSuffixes(Collection<String> suffixes) {
mySuffixes.addAll(suffixes);
}
}
@@ -0,0 +1,116 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.lang.properties.editor.inspections.incomplete;
import com.intellij.lang.properties.PropertiesUtil;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.*;
import com.intellij.ui.components.JBList;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.Locale;
import java.util.SortedSet;
/**
* @author Dmitry Batkovich
*/
public class IncompletePropertyInspectionOptionsPanel {
private final SortedSet<String> mySuffixes;
private final JBList myList;
public IncompletePropertyInspectionOptionsPanel(SortedSet<String> suffixes) {
mySuffixes = suffixes;
myList = new JBList(new MyListModel());
}
public JPanel buildPanel() {
JPanel panel = ToolbarDecorator
.createDecorator(myList)
.setPanelBorder(IdeBorderFactory.createTitledBorder("Ignored suffixes"))
.disableUpDownActions()
.setAddAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
final String result = Messages.showInputDialog(CommonDataKeys.PROJECT.getData(button.getDataContext()),
"Suffixes to ignore (use comma to separate suffixes):",
"Add Ignored Suffixes", null);
if (result != null) {
mySuffixes.addAll(StringUtil.split(result, ","));
changed();
}
}
}).setRemoveAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
for (Object v : myList.getSelectedValues()) {
mySuffixes.remove(v);
}
changed();
}
}).createPanel();
myList.setCellRenderer(new ColoredListCellRenderer<String>() {
@Override
protected void customizeCellRenderer(JList list, String suffix, int index, boolean selected, boolean hasFocus) {
append(suffix);
final Locale locale = PropertiesUtil.getLocale("_" + suffix + ".properties");
if (locale != PropertiesUtil.DEFAULT_LOCALE && PropertiesUtil.hasDefaultLanguage(locale)) {
append(" ");
append(PropertiesUtil.getPresentableLocale(locale), SimpleTextAttributes.GRAY_ATTRIBUTES);
}
}
});
return panel;
}
public boolean showDialogAndGet(Project project) {
return new DialogWrapper(project) {
{
init();
setTitle("Locales to Ignore");
}
@Nullable
@Override
protected JComponent createCenterPanel() {
return buildPanel();
}
}.showAndGet();
}
private void changed() {
((MyListModel)myList.getModel()).modified();
}
private class MyListModel extends AbstractListModel {
public int getSize() {
return mySuffixes.size();
}
public Object getElementAt(int index) {
return mySuffixes.toArray(new String[mySuffixes.size()])[index];
}
public void modified() {
fireContentsChanged(this, -1, -1);
}
}
}
@@ -15,7 +15,7 @@
*/
package com.intellij.lang.properties;
import com.intellij.lang.properties.editor.IgnoredPropertiesFilesSuffixesManager;
import com.intellij.lang.properties.editor.inspections.incomplete.IncompletePropertyInspection;
import com.intellij.lang.properties.psi.PropertiesFile;
import com.intellij.psi.PsiFile;
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
@@ -27,6 +27,12 @@ import java.util.Collections;
*/
public class IgnoredPropertiesFilesSuffixesTest extends LightPlatformCodeInsightFixtureTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
myFixture.enableInspections(IncompletePropertyInspection.class);
}
public void testPropertyIsComplete() {
myFixture.addFileToProject("p.properties", "key=value");
myFixture.addFileToProject("p_en.properties", "key=value eng");
@@ -35,9 +41,9 @@ public class IgnoredPropertiesFilesSuffixesTest extends LightPlatformCodeInsight
assertNotNull(propertiesFile);
final ResourceBundle resourceBundle = propertiesFile.getResourceBundle();
assertSize(3, resourceBundle.getPropertiesFiles());
final IgnoredPropertiesFilesSuffixesManager suffixesManager = IgnoredPropertiesFilesSuffixesManager.getInstance(getProject());
suffixesManager.addSuffixes(Collections.singleton("ru"));
assertTrue(suffixesManager.isPropertyComplete(resourceBundle, "key"));
final IncompletePropertyInspection incompletePropertyInspection = IncompletePropertyInspection.getInstance(propertiesFile.getContainingFile());
incompletePropertyInspection.addSuffixes(Collections.singleton("ru"));
assertTrue(incompletePropertyInspection.isPropertyComplete("key", resourceBundle));
}
public void testPropertyIsComplete2() {
@@ -48,8 +54,8 @@ public class IgnoredPropertiesFilesSuffixesTest extends LightPlatformCodeInsight
assertNotNull(propertiesFile);
final ResourceBundle resourceBundle = propertiesFile.getResourceBundle();
assertSize(3, resourceBundle.getPropertiesFiles());
final IgnoredPropertiesFilesSuffixesManager suffixesManager = IgnoredPropertiesFilesSuffixesManager.getInstance(getProject());
assertTrue(suffixesManager.isPropertyComplete(resourceBundle, "key"));
final IncompletePropertyInspection incompletePropertyInspection = IncompletePropertyInspection.getInstance(propertiesFile.getContainingFile());
assertTrue(incompletePropertyInspection.isPropertyComplete("key", resourceBundle));
}
public void testPropertyIsIncomplete() {
@@ -61,9 +67,9 @@ public class IgnoredPropertiesFilesSuffixesTest extends LightPlatformCodeInsight
assertNotNull(propertiesFile);
final ResourceBundle resourceBundle = propertiesFile.getResourceBundle();
assertSize(4, resourceBundle.getPropertiesFiles());
final IgnoredPropertiesFilesSuffixesManager suffixesManager = IgnoredPropertiesFilesSuffixesManager.getInstance(getProject());
suffixesManager.addSuffixes(Collections.singleton("ru"));
assertFalse(suffixesManager.isPropertyComplete(resourceBundle, "key"));
final IncompletePropertyInspection incompletePropertyInspection = IncompletePropertyInspection.getInstance(propertiesFile.getContainingFile());
incompletePropertyInspection.addSuffixes(Collections.singleton("ru"));
assertFalse(incompletePropertyInspection.isPropertyComplete("key", resourceBundle));
}
public void testPropertyIsIncomplete2() {
@@ -76,14 +82,8 @@ public class IgnoredPropertiesFilesSuffixesTest extends LightPlatformCodeInsight
assertNotNull(propertiesFile);
final ResourceBundle resourceBundle = propertiesFile.getResourceBundle();
assertSize(5, resourceBundle.getPropertiesFiles());
final IgnoredPropertiesFilesSuffixesManager suffixesManager = IgnoredPropertiesFilesSuffixesManager.getInstance(getProject());
suffixesManager.addSuffixes(Collections.singleton("en"));
assertFalse(suffixesManager.isPropertyComplete(resourceBundle, "key"));
}
@Override
public void tearDown() throws Exception {
IgnoredPropertiesFilesSuffixesManager.getInstance(getProject()).setSuffixes(Collections.<String>emptySet());
super.tearDown();
final IncompletePropertyInspection incompletePropertyInspection = IncompletePropertyInspection.getInstance(propertiesFile.getContainingFile());
incompletePropertyInspection.addSuffixes(Collections.singleton("en"));
assertFalse(incompletePropertyInspection.isPropertyComplete("key", resourceBundle));
}
}
@@ -0,0 +1,20 @@
<!--
~ Copyright 2000-2015 JetBrains s.r.o.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ 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.
-->
<html>
<body>
Inspection detects property keys which have no translations in part of resource bundle properties files.
</body>
</html>