Inspections

This commit is contained in:
Alexander Lobas
2012-05-29 20:58:25 +04:00
parent 469ff21210
commit ba2d5beff8
17 changed files with 291 additions and 18 deletions
@@ -17,6 +17,7 @@ package com.intellij.android.designer.inspection;
import com.android.tools.lint.detector.api.Issue;
import com.intellij.android.designer.model.RadViewComponent;
import com.intellij.android.designer.propertyTable.IXmlAttributeLocator;
import com.intellij.codeHighlighting.HighlightDisplayLevel;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInsight.intention.IntentionAction;
@@ -25,6 +26,7 @@ import com.intellij.designer.inspection.ErrorInfo;
import com.intellij.designer.inspection.QuickFix;
import com.intellij.designer.model.RadComponent;
import com.intellij.designer.model.RadComponentVisitor;
import com.intellij.designer.propertyTable.Property;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
@@ -71,9 +73,9 @@ public final class ErrorAnalyzer {
PsiElement endElement = xmlFile.findElementAt(range.getEndOffset() - 1);
if (startElement != null && endElement != null && !inspection.isSuppressedFor(startElement)) {
RadComponent component = findComponent(rootComponent, startElement);
ErrorInfo errorInfo = new ErrorInfo(message, null, pair.getSecond());
ErrorInfo.add(component, errorInfo);
Pair<RadComponent, String> componentInfo = findComponent(rootComponent, startElement);
ErrorInfo errorInfo = new ErrorInfo(message, componentInfo.second, pair.getSecond());
ErrorInfo.add(componentInfo.first, errorInfo);
List<QuickFix> designerFixes = errorInfo.getQuickFixes();
@@ -135,19 +137,18 @@ public final class ErrorAnalyzer {
}
}
private static RadComponent findComponent(RadComponent rootComponent, PsiElement element) {
Pair<XmlTag, XmlAttribute> tagInfo = extractTag(element);
private static Pair<RadComponent, String> findComponent(RadComponent rootComponent, PsiElement element) {
final Pair<XmlTag, XmlAttribute> tagInfo = extractTag(element);
if (tagInfo.first == null) {
return rootComponent;
return new Pair<RadComponent, String>(rootComponent, null);
}
final XmlTag tag = tagInfo.first;
final RadComponent[] result = new RadComponent[]{rootComponent};
rootComponent.accept(new RadComponentVisitor() {
@Override
public boolean visit(RadComponent component) {
if (tag == ((RadViewComponent)component).getTag()) {
if (tagInfo.first == ((RadViewComponent)component).getTag()) {
result[0] = component;
return false;
}
@@ -159,7 +160,18 @@ public final class ErrorAnalyzer {
}
}, true);
return result[0];
String propertyName = null;
if (tagInfo.second != null && result[0] != rootComponent) {
RadViewComponent component = (RadViewComponent)result[0];
for (Property property : component.getProperties()) {
if (((IXmlAttributeLocator)property).checkAttribute(component, tagInfo.second)) {
propertyName = property.getName();
break;
}
}
}
return new Pair<RadComponent, String>(result[0], propertyName);
}
private static Pair<XmlTag, XmlAttribute> extractTag(PsiElement element) {
@@ -37,7 +37,7 @@ import java.util.Set;
/**
* @author Alexander Lobas
*/
public class AttributeProperty extends Property<RadViewComponent> {
public class AttributeProperty extends Property<RadViewComponent> implements IXmlAttributeLocator {
protected final AttributeDefinition myDefinition;
private final PropertyRenderer myRenderer;
private final PropertyEditor myEditor;
@@ -125,6 +125,11 @@ public class AttributeProperty extends Property<RadViewComponent> {
return component.getTag().getAttribute("android:" + myDefinition.getName());
}
@Override
public boolean checkAttribute(RadViewComponent component, XmlAttribute attribute) {
return getAttribute(component) == attribute;
}
@NotNull
@Override
public PropertyRenderer getRenderer() {
@@ -23,6 +23,7 @@ import com.intellij.designer.propertyTable.PropertyEditor;
import com.intellij.designer.propertyTable.PropertyRenderer;
import com.intellij.designer.propertyTable.renderers.LabelPropertyRenderer;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.xml.XmlAttribute;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -32,7 +33,7 @@ import java.util.List;
/**
* @author Alexander Lobas
*/
public class CompoundProperty extends Property<RadViewComponent> implements IPropertyDecorator {
public class CompoundProperty extends Property<RadViewComponent> implements IPropertyDecorator, IXmlAttributeLocator {
private final List<Property<RadViewComponent>> myChildren = new ArrayList<Property<RadViewComponent>>();
private PropertyRenderer myRenderer;
@@ -126,4 +127,14 @@ public class CompoundProperty extends Property<RadViewComponent> implements IPro
public String getJavadocText() {
return myChildren.isEmpty() ? null : myChildren.get(0).getJavadocText();
}
@Override
public boolean checkAttribute(RadViewComponent component, XmlAttribute attribute) {
for (Property<RadViewComponent> childProperty : myChildren) {
if (((IXmlAttributeLocator)childProperty).checkAttribute(component, attribute)) {
return true;
}
}
return false;
}
}
@@ -17,6 +17,7 @@ package com.intellij.android.designer.propertyTable;
import com.intellij.android.designer.model.PropertyParser;
import com.intellij.android.designer.model.RadCustomViewComponent;
import com.intellij.android.designer.model.RadViewComponent;
import com.intellij.android.designer.propertyTable.editors.ResourceEditor;
import com.intellij.designer.model.RadComponent;
import com.intellij.designer.propertyTable.Property;
@@ -25,6 +26,7 @@ import com.intellij.designer.propertyTable.PropertyRenderer;
import com.intellij.designer.propertyTable.renderers.LabelPropertyRenderer;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlTag;
import org.jetbrains.android.dom.attrs.AttributeFormat;
import org.jetbrains.annotations.NotNull;
@@ -36,7 +38,7 @@ import java.util.List;
/**
* @author Alexander Lobas
*/
public class CustomViewProperty extends Property<RadCustomViewComponent> {
public class CustomViewProperty extends Property<RadCustomViewComponent> implements IXmlAttributeLocator {
private static final String JAVA_DOC = JavadocParser.build("view:class", "The fully qualified name of the class.");
private final PropertyRenderer myRenderer = new LabelPropertyRenderer(null);
private final PropertyEditor myEditor = new ResourceEditor(null, Collections.<AttributeFormat>emptySet(), null) {
@@ -125,4 +127,9 @@ public class CustomViewProperty extends Property<RadCustomViewComponent> {
public String getJavadocText() {
return JAVA_DOC;
}
@Override
public boolean checkAttribute(RadViewComponent component, XmlAttribute attribute) {
return component.getTag().getAttribute("class") == attribute;
}
}
@@ -36,7 +36,7 @@ import java.util.*;
/**
* @author Alexander Lobas
*/
public class FlagProperty extends Property<RadViewComponent> implements IPropertyDecorator {
public class FlagProperty extends Property<RadViewComponent> implements IPropertyDecorator, IXmlAttributeLocator {
private final PropertyRenderer myRenderer = new LabelPropertyRenderer(null);
protected final AttributeDefinition myDefinition;
protected final List<Property<RadViewComponent>> myOptions = new ArrayList<Property<RadViewComponent>>();
@@ -119,6 +119,11 @@ public class FlagProperty extends Property<RadViewComponent> implements IPropert
return component.getTag().getAttribute("android:" + myDefinition.getName());
}
@Override
public boolean checkAttribute(RadViewComponent component, XmlAttribute attribute) {
return getAttribute(component) == attribute;
}
protected Set<String> getOptions(RadViewComponent component) throws Exception {
String value = component.getTag().getAttributeValue("android:" + myDefinition.getName());
if (value == null) {
@@ -24,6 +24,7 @@ import com.intellij.designer.propertyTable.PropertyRenderer;
import com.intellij.designer.propertyTable.renderers.LabelPropertyRenderer;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.xml.XmlAttribute;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -32,7 +33,7 @@ import java.util.List;
/**
* @author Alexander Lobas
*/
public class FragmentProperty extends Property<RadViewComponent> {
public class FragmentProperty extends Property<RadViewComponent> implements IXmlAttributeLocator {
private final String myAttribute;
private final PropertyRenderer myRenderer = new LabelPropertyRenderer(null);
private final PropertyEditor myEditor;
@@ -104,4 +105,9 @@ public class FragmentProperty extends Property<RadViewComponent> {
public String getJavadocText() {
return myJavadocText;
}
@Override
public boolean checkAttribute(RadViewComponent component, XmlAttribute attribute) {
return component.getTag().getAttribute(myAttribute) == attribute;
}
}
@@ -0,0 +1,26 @@
/*
* Copyright 2000-2012 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.android.designer.propertyTable;
import com.intellij.android.designer.model.RadViewComponent;
import com.intellij.psi.xml.XmlAttribute;
/**
* @author Alexander Lobas
*/
public interface IXmlAttributeLocator {
boolean checkAttribute(RadViewComponent component, XmlAttribute attribute);
}
@@ -25,6 +25,7 @@ import com.intellij.designer.propertyTable.PropertyEditor;
import com.intellij.designer.propertyTable.PropertyRenderer;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.xml.XmlAttribute;
import org.jetbrains.android.dom.attrs.AttributeFormat;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -36,7 +37,7 @@ import java.util.Set;
/**
* @author Alexander Lobas
*/
public class IncludeLayoutProperty extends Property<RadViewComponent> {
public class IncludeLayoutProperty extends Property<RadViewComponent> implements IXmlAttributeLocator {
public static final String NAME = "layout:xml";
public static ResourceType[] TYPES = new ResourceType[]{ResourceType.LAYOUT};
private static final Set<AttributeFormat> FORMATS = EnumSet.of(AttributeFormat.Reference);
@@ -94,4 +95,9 @@ public class IncludeLayoutProperty extends Property<RadViewComponent> {
public String getJavadocText() {
return JAVA_DOC;
}
@Override
public boolean checkAttribute(RadViewComponent component, XmlAttribute attribute) {
return component.getTag().getAttribute("layout") == attribute;
}
}
@@ -134,6 +134,15 @@ public final class DesignerToolWindowManager implements ProjectComponent {
}
}
public void updateInspections() {
if (myComponentTree != null) {
myComponentTree.updateInspections();
}
if (myPropertyTablePanel != null) {
myPropertyTablePanel.getPropertyTable().updateInspections();
}
}
@Nullable
private static DesignerEditorPanel getDesigner(FileEditor editor) {
if (editor instanceof DesignerEditor) {
@@ -186,6 +195,7 @@ public final class DesignerToolWindowManager implements ProjectComponent {
JScrollPane treeScrollPane = ScrollPaneFactory.createScrollPane(myComponentTree);
treeScrollPane.setBorder(IdeBorderFactory.createBorder(SideBorder.BOTTOM));
treeScrollPane.setPreferredSize(new Dimension(250, -1));
myComponentTree.initQuickFixManager(treeScrollPane.getViewport());
myPropertyTablePanel = new PropertyTablePanel();
@@ -39,6 +39,7 @@ import java.awt.*;
*/
public final class ComponentTree extends Tree implements DataProvider {
private final StartInplaceEditing myInplaceEditingAction;
private QuickFixManager myQuickFixManager;
private TreeComponentDecorator myDecorator;
private DesignerActionPanel myActionPanel;
private EditableArea myArea;
@@ -67,6 +68,14 @@ public final class ComponentTree extends Tree implements DataProvider {
setModel(new DefaultTreeModel(new DefaultMutableTreeNode()));
}
public void initQuickFixManager(JViewport viewPort) {
myQuickFixManager = new QuickFixManager(this, viewPort);
}
public void updateInspections() {
myQuickFixManager.update();
}
public void setDesignerPanel(@Nullable DesignerEditorPanel designer) {
if (designer == null) {
myDecorator = null;
@@ -79,10 +88,12 @@ public final class ComponentTree extends Tree implements DataProvider {
myMarkComponent = null;
myArea = null;
myInplaceEditingAction.setDesignerPanel(designer);
myQuickFixManager.setDesigner(designer);
}
public void setArea(@Nullable EditableArea area) {
myArea = area;
myQuickFixManager.setEditableArea(area);
}
public void mark(RadComponent component, int feedback) {
@@ -0,0 +1,66 @@
/*
* Copyright 2000-2012 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.designer.componentTree;
import com.intellij.designer.designSurface.ComponentSelectionListener;
import com.intellij.designer.designSurface.EditableArea;
import com.intellij.designer.inspection.AbstractQuickFixManager;
import com.intellij.designer.inspection.ErrorInfo;
import com.intellij.designer.model.RadComponent;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.util.Collections;
import java.util.List;
/**
* @author Alexander Lobas
*/
public final class QuickFixManager extends AbstractQuickFixManager implements ComponentSelectionListener {
private EditableArea myArea;
public QuickFixManager(JComponent component, JViewport viewPort) {
super(null, component, viewPort);
}
public void setEditableArea(EditableArea area) {
myArea = area;
area.addSelectionListener(this);
}
@Override
public void selectionChanged(EditableArea area) {
hideHint();
updateHintVisibility();
}
@NotNull
@Override
protected List<ErrorInfo> getErrorInfos() {
List<RadComponent> selection = myArea.getSelection();
if (selection.size() == 1) {
return ErrorInfo.get(selection.get(0));
}
return Collections.emptyList();
}
@Override
protected Rectangle getErrorBounds() {
ComponentTree component = (ComponentTree)myComponent;
return component.getPathBounds(component.getSelectionPath());
}
}
@@ -28,7 +28,7 @@ import java.util.List;
/**
* @author Alexander Lobas
*/
public class QuickFixManager extends AbstractQuickFixManager implements ComponentSelectionListener {
public final class QuickFixManager extends AbstractQuickFixManager implements ComponentSelectionListener {
public QuickFixManager(DesignerEditorPanel designer, JComponent component, JViewport viewPort) {
super(designer, component, viewPort);
designer.getSurfaceArea().addSelectionListener(this);
@@ -60,7 +60,7 @@ public abstract class AbstractQuickFixManager {
private LightweightHint myHint;
private Rectangle myLastHintBounds;
public AbstractQuickFixManager(DesignerEditorPanel designer, JComponent component, JViewport viewPort) {
public AbstractQuickFixManager(@Nullable DesignerEditorPanel designer, JComponent component, JViewport viewPort) {
myDesigner = designer;
myComponent = component;
myViewPort = viewPort;
@@ -125,7 +125,7 @@ public abstract class AbstractQuickFixManager {
});
}
public void setDesigner(DesignerEditorPanel designer) {
public void setDesigner(@Nullable DesignerEditorPanel designer) {
myDesigner = designer;
}
@@ -16,6 +16,7 @@
package com.intellij.designer.inspection;
import com.intellij.codeHighlighting.HighlightingPass;
import com.intellij.designer.DesignerToolWindowManager;
import com.intellij.designer.designSurface.DesignerEditorPanel;
import com.intellij.openapi.progress.ProgressIndicator;
@@ -36,6 +37,7 @@ public final class DesignerHighlightingPass implements HighlightingPass {
@Override
public void applyInformationToEditor() {
DesignerToolWindowManager.getInstance(myDesigner.getProject()).updateInspections();
myDesigner.updateInspections();
}
}
@@ -19,6 +19,7 @@ import com.intellij.designer.DesignerBundle;
import com.intellij.designer.designSurface.ComponentSelectionListener;
import com.intellij.designer.designSurface.DesignerEditorPanel;
import com.intellij.designer.designSurface.EditableArea;
import com.intellij.designer.inspection.ErrorInfo;
import com.intellij.designer.model.RadComponent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.ui.Messages;
@@ -73,6 +74,8 @@ public final class PropertyTable extends JBTable implements ComponentSelectionLi
private boolean myShowExpert;
private QuickFixManager myQuickFixManager;
public PropertyTable() {
setModel(myModel);
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
@@ -90,6 +93,10 @@ public final class PropertyTable extends JBTable implements ComponentSelectionLi
// TODO: Updates UI after LAF updated
}
public void initQuickFixManager(JViewport viewPort) {
myQuickFixManager = new QuickFixManager(this, viewPort);
}
public void setUI(TableUI ui) {
super.setUI(ui);
@@ -139,6 +146,7 @@ public final class PropertyTable extends JBTable implements ComponentSelectionLi
public void setArea(@Nullable DesignerEditorPanel designer, @Nullable EditableArea area) {
myDesigner = designer;
myInitialSelection = designer == null ? null : designer.getSelectionProperty();
myQuickFixManager.setDesigner(designer);
finishEditing();
@@ -155,6 +163,10 @@ public final class PropertyTable extends JBTable implements ComponentSelectionLi
updateProperties();
}
public void updateInspections() {
myQuickFixManager.update();
}
@Override
public void selectionChanged(EditableArea area) {
updateProperties();
@@ -191,6 +203,21 @@ public final class PropertyTable extends JBTable implements ComponentSelectionLi
}
}
@Nullable
public ErrorInfo getErrorInfoForRow(int row) {
if (myComponents.size() != 1) {
return null;
}
Property property = myProperties.get(row);
for (ErrorInfo errorInfo : ErrorInfo.get(myComponents.get(0))) {
if (property.getName().equals(errorInfo.getPropertyName())) {
return errorInfo;
}
}
return null;
}
//////////////////////////////////////////////////////////////////////////////////////////
//
//
@@ -80,6 +80,7 @@ public final class PropertyTablePanel extends JPanel implements ListSelectionLis
JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(myPropertyTable);
scrollPane.setBorder(IdeBorderFactory.createBorder(SideBorder.TOP));
myPropertyTable.initQuickFixManager(scrollPane.getViewport());
add(scrollPane, new GridBagConstraints(0, 1, myActions.length + 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 0), 0, 0));
}
@@ -0,0 +1,78 @@
/*
* Copyright 2000-2012 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.designer.propertyTable;
import com.intellij.designer.inspection.AbstractQuickFixManager;
import com.intellij.designer.inspection.ErrorInfo;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* @author Alexander Lobas
*/
public final class QuickFixManager extends AbstractQuickFixManager implements ListSelectionListener {
public QuickFixManager(PropertyTable component, JViewport viewPort) {
super(null, component, viewPort);
component.getSelectionModel().addListSelectionListener(this);
}
@Override
public void valueChanged(ListSelectionEvent e) {
hideHint();
updateHintVisibility();
}
@NotNull
@Override
protected List<ErrorInfo> getErrorInfos() {
PropertyTable component = (PropertyTable)myComponent;
int selectedRow = component.getSelectedRow();
if (selectedRow < 0 || selectedRow >= component.getRowCount()) {
return Collections.emptyList();
}
ErrorInfo errorInfo = component.getErrorInfoForRow(selectedRow);
if (errorInfo != null) {
return Arrays.asList(errorInfo);
}
return Collections.emptyList();
}
@Override
protected Rectangle getErrorBounds() {
PropertyTable component = (PropertyTable)myComponent;
int selectedRow = component.getSelectedRow();
if (selectedRow < 0 || selectedRow >= component.getRowCount()) {
return null;
}
Rectangle rowRect = component.getCellRect(selectedRow, 0, true);
Rectangle visibleRect = myComponent.getVisibleRect();
if (visibleRect.intersects(rowRect)) {
return visibleRect.intersection(rowRect);
}
return null;
}
}