diff --git a/comparing_references_inspection/source/com/intellij/codeInspection/ComparingReferencesInspection.java b/comparing_references_inspection/source/com/intellij/codeInspection/ComparingReferencesInspection.java index fe87c0171..b7330bb8c 100644 --- a/comparing_references_inspection/source/com/intellij/codeInspection/ComparingReferencesInspection.java +++ b/comparing_references_inspection/source/com/intellij/codeInspection/ComparingReferencesInspection.java @@ -17,7 +17,7 @@ import java.util.StringTokenizer; /** * @author max */ -public class ComparingReferencesInspection extends BaseJavaLocalInspectionTool { +public class ComparingReferencesInspection extends AbstractBaseJavaLocalInspectionTool { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ComparingReferencesInspection"); private final LocalQuickFix myQuickFix = new MyQuickFix(); diff --git a/comparing_references_inspection/testSource/testPlugin/TestThisPlugin.java b/comparing_references_inspection/testSource/testPlugin/TestThisPlugin.java index 42d7a5d48..818494431 100644 --- a/comparing_references_inspection/testSource/testPlugin/TestThisPlugin.java +++ b/comparing_references_inspection/testSource/testPlugin/TestThisPlugin.java @@ -4,25 +4,32 @@ package testPlugin; import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInspection.ComparingReferencesInspection; +import com.intellij.codeInspection.InspectionToolProvider; +import com.intellij.testFramework.TestDataPath; import com.intellij.testFramework.UsefulTestCase; import com.intellij.testFramework.builders.JavaModuleFixtureBuilder; import com.intellij.testFramework.fixtures.*; -import junit.framework.Assert; +import org.junit.Assert; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** * @see JavaCodeInsightFixtureTestCase * @see LightCodeInsightFixtureTestCase */ +@TestDataPath("$CONTENT_ROOT/../testData") public class TestThisPlugin extends UsefulTestCase { protected CodeInsightTestFixture myFixture; + + // TODO: Get path to module root, then add path to testData // Specify path to your test data directory // e.g. final String dataPath = "c:\\users\\john.doe\\idea\\community\\samples\\ComparingReferences/testData"; final String dataPath = "c:\\users\\John.Doe\\idea\\community\\samples\\comparingReferences/testData"; - + public void setUp() throws Exception { final IdeaTestFixtureFactory fixtureFactory = IdeaTestFixtureFactory.getFixtureFactory(); @@ -44,6 +51,7 @@ public class TestThisPlugin extends UsefulTestCase { protected void doTest(String testName, String hint) throws Throwable { myFixture.configureByFile(testName + ".java"); + myFixture.enableInspections(ComparingReferencesInspection.class); List highlightInfos = myFixture.doHighlighting(); Assert.assertTrue(!highlightInfos.isEmpty()); diff --git a/facet_basics/resources/META-INF/plugin.xml b/facet_basics/resources/META-INF/plugin.xml index f05b42f7c..d7b342def 100644 --- a/facet_basics/resources/META-INF/plugin.xml +++ b/facet_basics/resources/META-INF/plugin.xml @@ -1,14 +1,37 @@ + + - com.intellij.tutorials.facet - Facet Demo - 1.0 - JetBrains - Basic example of adding support for custom Facets + + org.intellij.sdk.facet - + + SDK Facet Basics + + + + Adds SDK Facet to the Project Structure | Project Settings | Facets menu. + ]]> + + + 2.0 Refactored to illustrate use of PersistentComponent.
+ 1.0 Release 2018.3 and earlier. + ]]> +
+ + + IntelliJ Platform SDK + + + 2.0 + + + + diff --git a/facet_basics/src/com/intellij/tutorials/facet/DemoFacet.java b/facet_basics/src/com/intellij/tutorials/facet/DemoFacet.java index d521c6b39..e0b00cf3b 100644 --- a/facet_basics/src/com/intellij/tutorials/facet/DemoFacet.java +++ b/facet_basics/src/com/intellij/tutorials/facet/DemoFacet.java @@ -1,13 +1,16 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + package com.intellij.tutorials.facet; -import com.intellij.facet.*; +import com.intellij.facet.Facet; +import com.intellij.facet.FacetType; import com.intellij.openapi.module.Module; /** + * Demo Facet class. Everything is handled by the super class. * @author Anna Bulenkova */ public class DemoFacet extends Facet { - public static final String ID = "DEMO_FACET_ID"; public DemoFacet(FacetType facetType, Module module, @@ -16,4 +19,5 @@ public class DemoFacet extends Facet { Facet underlyingFacet) { super(facetType, module, name, configuration, underlyingFacet); } + } diff --git a/facet_basics/src/com/intellij/tutorials/facet/DemoFacetConfiguration.java b/facet_basics/src/com/intellij/tutorials/facet/DemoFacetConfiguration.java index 91e11a88d..159752fe1 100644 --- a/facet_basics/src/com/intellij/tutorials/facet/DemoFacetConfiguration.java +++ b/facet_basics/src/com/intellij/tutorials/facet/DemoFacetConfiguration.java @@ -1,76 +1,61 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + package com.intellij.tutorials.facet; import com.intellij.facet.FacetConfiguration; -import com.intellij.facet.ui.*; -import com.intellij.openapi.util.*; -import org.jdom.Element; -import org.jetbrains.annotations.*; - -import javax.swing.*; -import java.awt.*; +import com.intellij.facet.ui.FacetEditorContext; +import com.intellij.facet.ui.FacetEditorTab; +import com.intellij.facet.ui.FacetValidatorsManager; +import com.intellij.openapi.components.PersistentStateComponent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** + * Provides a custom implementation of the Configuration class for DemoFacet. + * * @author Anna Bulenkova + * @author John Hake */ -public class DemoFacetConfiguration implements FacetConfiguration { - public static final String DEMO_FACET_TAG_NAME = "DemoFacet"; - public static final String PATH_TO_SDK_ATTR_NAME = "pathToSdk"; - private String myPathToSdk = ""; - JTextField myPath = new JTextField(myPathToSdk); +public class DemoFacetConfiguration implements FacetConfiguration, PersistentStateComponent { + // Manages the data stored with this facet. + private DemoFacetState myFacetState = new DemoFacetState(); + + /** + * Called by the IntelliJ Platform when saving this facet's state persistently. + * @return a component state. All properties, public and annotated fields are serialized. + * Only values which differ from default (i.e. the value of newly instantiated class) are serialized. + * {@code null} value indicates that the returned state won't be stored, and + * as a result previously stored state will be used. + */ + @Nullable + @Override + public DemoFacetState getState() { + return myFacetState; + } + + /** + * Called by the IntelliJ Platform when this facet's state is loaded. + * The method can and will be called several times, if + * config files were externally changed while IDEA running. + */ + @Override + public void loadState(@NotNull DemoFacetState state) { + myFacetState = state; + } + + /** + * Creates a set of editor tabs for this facet, potentially one per context. + * + * @param context The context in which a facet is being added/deleted, or modified. + * @param manager The manager which can be used to access custom validators. + * @return Array of DemoFacetEditorTabs. In this case size is always 1. + */ @Override public FacetEditorTab[] createEditorTabs(FacetEditorContext context, FacetValidatorsManager manager) { return new FacetEditorTab[]{ - new FacetEditorTab() { - - @NotNull - @Override - public JComponent createComponent() { - JPanel top = new JPanel(new BorderLayout()); - top.add(new JLabel("Path to SDK: "), BorderLayout.WEST); - top.add(myPath); - JPanel panel = new JPanel(new BorderLayout()); - panel.add(top, BorderLayout.NORTH); - return panel; - } - - @Nls - @Override - public String getDisplayName() { - return "Demo Framework"; - } - - @Override - public boolean isModified() { - return myPath.getText().equalsIgnoreCase(myPathToSdk); -// return !StringUtil.equalsIgnoreWhitespaces(myPath.getText(), myPathToSdk); - } - - @Override - public void reset() { - myPath.setText(myPathToSdk); - } - - @Override - public void disposeUIResources() { - } - } + new DemoFacetEditorTab(myFacetState, context, manager) }; } - @Override - public void readExternal(Element element) throws InvalidDataException { - Element facet = element.getChild(DEMO_FACET_TAG_NAME); - if (facet != null) { - myPathToSdk = facet.getAttributeValue(PATH_TO_SDK_ATTR_NAME, ""); - myPath.setText(myPathToSdk); - } - } - - @Override - public void writeExternal(Element element) throws WriteExternalException { - Element facet = new Element(DEMO_FACET_TAG_NAME); - facet.setAttribute(PATH_TO_SDK_ATTR_NAME, myPathToSdk); - element.addContent(facet); - } } diff --git a/facet_basics/src/com/intellij/tutorials/facet/DemoFacetEditorTab.java b/facet_basics/src/com/intellij/tutorials/facet/DemoFacetEditorTab.java new file mode 100644 index 000000000..e2a142e28 --- /dev/null +++ b/facet_basics/src/com/intellij/tutorials/facet/DemoFacetEditorTab.java @@ -0,0 +1,107 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.tutorials.facet; + +import com.intellij.facet.ui.FacetEditorContext; +import com.intellij.facet.ui.FacetEditorTab; +import com.intellij.facet.ui.FacetValidatorsManager; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.util.Comparing; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; + +/** + * Provides the JPanel to be displayed in the facet UI. + * Manages validation and modification of the DemoFacet state. + * + * @author John Hake + */ +public class DemoFacetEditorTab extends FacetEditorTab { + private static final String FACET_PANEL_PROMPT = "Path To SDK: "; + + private final DemoFacetState mySettings; + private final JTextField myPath; + + /** + * Only DemoFacetState is captured so it can be updated per user changes + * in the EditorTab. + * + * @param state DemoFacetState object persisting DemoFacet state. + * @param context Facet editor context, can be used to get e.g. the current project module. + * @param validator Facet validator manager, can be used to get and apply a custom validator for + * this facet. + */ + public DemoFacetEditorTab(@NotNull DemoFacetState state, @NotNull FacetEditorContext context, @NotNull FacetValidatorsManager validator) { + mySettings = state; + myPath = new JTextField(state.getDemoFacetState()); + } + + /** + * Provides the JPanel displayed in the Preferences | Facet UI + * + * @return JPanel to be displayed in the DemoFacetEditorTab. + */ + @NotNull + @Override + public JComponent createComponent() { + JPanel top = new JPanel(new BorderLayout()); + top.add(new JLabel(FACET_PANEL_PROMPT), BorderLayout.WEST); + top.add(myPath); + JPanel facetPanel = new JPanel(new BorderLayout()); + facetPanel.add(top, BorderLayout.NORTH); + return facetPanel; + } + + + /** + * @return the name of this facet for display in this editor tab. + */ + @Override + @Nls(capitalization = Nls.Capitalization.Title) + public String getDisplayName() { + return DemoFacetType.FACET_NAME; + } + + /** + * Determines if the facet state entered in the UI differs + * from the currently stored state. + * Called when user changes text in myPath. + * + * @return {@code true} if the state returned from the panel's UI + * differs from the stored facet state. + */ + @Override + public boolean isModified() { + boolean foo = !Comparing.equal(mySettings.getDemoFacetState(), myPath.getText().trim()); + return foo; + } + + /** + * Stores new facet state (text) entered by the user. + * Called when {@link #isModified()} returns true. + * @throws ConfigurationException if anything generates an exception. + */ + @Override + public void apply() throws ConfigurationException { + // Not much to go wrong here, but fulfill the contract + try { + String newTextContent = myPath.getText(); + mySettings.setDemoFacetState(newTextContent); + } catch(Exception e) { + throw new ConfigurationException(e.toString()); + } + } + + /** + * Copies current DemoFacetState into the myPath UI element. + * This method is called each time this editor tab is needed for display. + */ + @Override + public void reset() { + myPath.setText(mySettings.getDemoFacetState()); + } + +} diff --git a/facet_basics/src/com/intellij/tutorials/facet/DemoFacetState.java b/facet_basics/src/com/intellij/tutorials/facet/DemoFacetState.java new file mode 100644 index 000000000..fbe011bcf --- /dev/null +++ b/facet_basics/src/com/intellij/tutorials/facet/DemoFacetState.java @@ -0,0 +1,32 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + +package com.intellij.tutorials.facet; + +import org.jetbrains.annotations.NotNull; + +/** + * A simple class to store state for the DemoFacet. + * In this case it is just a string containing a path to an SDK. + * + * @author John Hake + */ +public class DemoFacetState { + static final String DEMO_FACET_INIT_PATH = ""; + + public String myPathToSdk; + + DemoFacetState() { + setDemoFacetState(DEMO_FACET_INIT_PATH); + } + + @NotNull + public String getDemoFacetState() { + return myPathToSdk; + } + + public void setDemoFacetState(@NotNull String newPath) { + myPathToSdk = newPath; + } + + +} diff --git a/facet_basics/src/com/intellij/tutorials/facet/DemoFacetType.java b/facet_basics/src/com/intellij/tutorials/facet/DemoFacetType.java index db3b991ef..d6c845391 100644 --- a/facet_basics/src/com/intellij/tutorials/facet/DemoFacetType.java +++ b/facet_basics/src/com/intellij/tutorials/facet/DemoFacetType.java @@ -1,3 +1,5 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. + package com.intellij.tutorials.facet; import com.intellij.facet.*; @@ -8,13 +10,19 @@ import org.jetbrains.annotations.*; import javax.swing.*; /** + * Defines the type, id, and name of the DemoFacet. Provides creation of DemoFacet + * and associated Configuration. + * Allows application of this facet to all ModuleTypes. + * * @author Anna Bulenkova */ public class DemoFacetType extends FacetType { - private static final FacetTypeId TYPE_ID = new FacetTypeId(DemoFacet.ID); + public static final String FACET_ID = "DEMO_FACET_ID"; + public static final String FACET_NAME = "SDK Facet"; + public static final FacetTypeId DEMO_FACET_TYPE_ID = new FacetTypeId(FACET_ID); public DemoFacetType() { - super(TYPE_ID, DemoFacet.ID, "Demo Facet"); + super(DEMO_FACET_TYPE_ID, FACET_ID, FACET_NAME); } @Override @@ -31,7 +39,7 @@ public class DemoFacetType extends FacetType } @Override - public boolean isSuitableModuleType(ModuleType type) { + public boolean isSuitableModuleType(final ModuleType type) { return true; } diff --git a/plugin_sample/resources/META-INF/plugin.xml b/plugin_sample/resources/META-INF/plugin.xml index ff65c8c65..c5a4a39d9 100644 --- a/plugin_sample/resources/META-INF/plugin.xml +++ b/plugin_sample/resources/META-INF/plugin.xml @@ -58,14 +58,6 @@ - - - - org.jetbrains.tutorials.sample.DummyModuleComponent - org.jetbrains.tutorials.sample.DummyModuleComponentImpl - - -