From 3e7de1cfb616b5aa6b4a49aba27e149aa51bf9e0 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Mon, 27 Aug 2012 13:53:16 +0400 Subject: [PATCH] Added ExternalAnnotationsListener. It is invoked at the end of external annotations modification commands and when all caches are dropped (e.g., module roots changed) --- .../ExternalAnnotationsManagerImpl.java | 43 +++++++++++++-- .../ExternalAnnotationsListener.java | 52 +++++++++++++++++++ .../ExternalAnnotationsManager.java | 3 ++ 3 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 java/java-psi-api/src/com/intellij/codeInsight/ExternalAnnotationsListener.java diff --git a/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java index bb00fcec761c..4cc4a62bf167 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java @@ -69,6 +69,7 @@ import com.intellij.psi.xml.XmlDocument; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; import com.intellij.util.*; +import com.intellij.util.messages.MessageBus; import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.ui.OptionsMessageDialog; import org.jetbrains.annotations.NonNls; @@ -86,18 +87,29 @@ public class ExternalAnnotationsManagerImpl extends BaseExternalAnnotationsManag private static final Logger LOG = Logger.getInstance("#" + ExternalAnnotationsManagerImpl.class.getName()); @NotNull private volatile ThreeState myHasAnyAnnotationsRoots = ThreeState.UNSURE; + private final MessageBus myBus; public ExternalAnnotationsManagerImpl(@NotNull final Project project, final PsiManager psiManager) { super(psiManager); - final MessageBusConnection connection = project.getMessageBus().connect(project); + myBus = project.getMessageBus(); + final MessageBusConnection connection = myBus.connect(project); connection.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootAdapter() { @Override public void rootsChanged(ModuleRootEvent event) { dropCache(); + notifyChangedDramatically(); } }); } + private void notifyAfterAnnotationChanging(@NotNull PsiModifierListOwner owner, @NotNull String annotationFQName, boolean successful) { + myBus.syncPublisher(TOPIC).afterExternalAnnotationChanging(owner, annotationFQName, successful); + } + + private void notifyChangedDramatically() { + myBus.syncPublisher(TOPIC).externalAnnotationsChangedDramatically(); + } + @Override protected void dropCache() { super.dropCache(); @@ -131,6 +143,7 @@ public class ExternalAnnotationsManagerImpl extends BaseExternalAnnotationsManag final Project project = myPsiManager.getProject(); final PsiFile containingFile = listOwner.getContainingFile(); if (!(containingFile instanceof PsiJavaFile)) { + notifyAfterAnnotationChanging(listOwner, annotationFQName, false); return; } final String packageName = ((PsiJavaFile)containingFile).getPackageName(); @@ -138,6 +151,7 @@ public class ExternalAnnotationsManagerImpl extends BaseExternalAnnotationsManag LOG.assertTrue(containingVirtualFile != null); final List entries = ProjectRootManager.getInstance(project).getFileIndex().getOrderEntriesForFile(containingVirtualFile); if (entries.isEmpty()) { + notifyAfterAnnotationChanging(listOwner, annotationFQName, false); return; } for (final OrderEntry entry : entries) { @@ -150,6 +164,7 @@ public class ExternalAnnotationsManagerImpl extends BaseExternalAnnotationsManag } else { if (ApplicationManager.getApplication().isUnitTestMode() || ApplicationManager.getApplication().isHeadlessEnvironment()) { + notifyAfterAnnotationChanging(listOwner, annotationFQName, false); return; } SwingUtilities.invokeLater(new Runnable() { @@ -190,6 +205,7 @@ public class ExternalAnnotationsManagerImpl extends BaseExternalAnnotationsManag descriptor.setDescription(ProjectBundle.message("external.annotations.root.chooser.description")); final VirtualFile newRoot = FileChooser.chooseFile(descriptor, project, null); if (newRoot == null) { + notifyAfterAnnotationChanging(listOwner, annotationFQName, false); return; } new WriteCommandAction(project) { @@ -198,7 +214,10 @@ public class ExternalAnnotationsManagerImpl extends BaseExternalAnnotationsManag appendChosenAnnotationsRoot(entry, newRoot); XmlFile xmlFileInRoot = findXmlFileInRoot(findExternalAnnotationsXmlFiles(listOwner), newRoot); if (xmlFileInRoot != null) { //file already exists under appeared content root - if (!CodeInsightUtilBase.preparePsiElementForWrite(xmlFileInRoot)) return; + if (!CodeInsightUtilBase.preparePsiElementForWrite(xmlFileInRoot)) { + notifyAfterAnnotationChanging(listOwner, annotationFQName, false); + return; + } annotateExternally(listOwner, annotationFQName, xmlFileInRoot, fromFile, value); } else { @@ -241,6 +260,11 @@ public class ExternalAnnotationsManagerImpl extends BaseExternalAnnotationsManag final PsiNameValuePair[] value) { if (roots.length > 1) { JBPopupFactory.getInstance().createListPopup(new BaseListPopupStep("Annotation Roots", roots) { + @Override + public void canceled() { + notifyAfterAnnotationChanging(listOwner, annotationFQName, false); + } + @Override public PopupStep onChosen(@NotNull final VirtualFile file, final boolean finalChoice) { annotateExternally(file, listOwner, project, packageName, annotationFQName, fromFile, value); @@ -306,6 +330,9 @@ public class ExternalAnnotationsManagerImpl extends BaseExternalAnnotationsManag myExternalAnnotations.put(getFQN(packageName, fromFile), annotationFiles); annotateExternally(listOwner, annotationFQName, annotationsXml[0], fromFile, value); } + else { + notifyAfterAnnotationChanging(listOwner, annotationFQName, false); + } } }.execute(); @@ -313,11 +340,13 @@ public class ExternalAnnotationsManagerImpl extends BaseExternalAnnotationsManag @Override public void undo() throws UnexpectedUndoException { dropCache(); + notifyChangedDramatically(); } @Override public void redo() throws UnexpectedUndoException { dropCache(); + notifyChangedDramatically(); } }); } @@ -358,6 +387,7 @@ public class ExternalAnnotationsManagerImpl extends BaseExternalAnnotationsManag try { final List files = findExternalAnnotationsXmlFiles(listOwner); if (files == null) { + notifyAfterAnnotationChanging(listOwner, annotationFQN, false); return false; } boolean processedAnything = false; @@ -404,6 +434,7 @@ public class ExternalAnnotationsManagerImpl extends BaseExternalAnnotationsManag } } } + notifyAfterAnnotationChanging(listOwner, annotationFQN, processedAnything); return processedAnything; } finally { @@ -503,7 +534,10 @@ public class ExternalAnnotationsManagerImpl extends BaseExternalAnnotationsManag @Nullable final XmlFile xmlFile, @NotNull final PsiFile codeUsageFile, final PsiNameValuePair[] values) { - if (xmlFile == null) return; + if (xmlFile == null) { + notifyAfterAnnotationChanging(listOwner, annotationFQName, false); + return; + } CommandProcessor.getInstance().executeCommand(myPsiManager.getProject(), new Runnable() { @Override public void run() { @@ -524,6 +558,7 @@ public class ExternalAnnotationsManagerImpl extends BaseExternalAnnotationsManag tag.add(XmlElementFactory.getInstance(myPsiManager.getProject()).createTagFromText( createAnnotationTag(annotationFQName, values))); commitChanges(xmlFile); + notifyAfterAnnotationChanging(listOwner, annotationFQName, true); return; } } @@ -535,9 +570,11 @@ public class ExternalAnnotationsManagerImpl extends BaseExternalAnnotationsManag } } commitChanges(xmlFile); + notifyAfterAnnotationChanging(listOwner, annotationFQName, true); } catch (IncorrectOperationException e) { LOG.error(e); + notifyAfterAnnotationChanging(listOwner, annotationFQName, false); } finally { dropCache(); diff --git a/java/java-psi-api/src/com/intellij/codeInsight/ExternalAnnotationsListener.java b/java/java-psi-api/src/com/intellij/codeInsight/ExternalAnnotationsListener.java new file mode 100644 index 000000000000..79e63766eae4 --- /dev/null +++ b/java/java-psi-api/src/com/intellij/codeInsight/ExternalAnnotationsListener.java @@ -0,0 +1,52 @@ +/* + * 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.codeInsight; + +import com.intellij.psi.PsiModifierListOwner; +import org.jetbrains.annotations.NotNull; + +import java.util.EventListener; + +/** + * @author Evgeny Gerashchenko + * @since 27 Aug 2012 + */ +public interface ExternalAnnotationsListener extends EventListener { + /** + * Invoked at the end of annotateExternally/editExternalAnnotation/deannotate work. + * It's invoked in both cases: either it was completed successfully or not. + * + * @param owner annotation owner + * @param annotationFQName annotation class FQ name + * @param successful if annotation modification was successful + */ + void afterExternalAnnotationChanging(@NotNull PsiModifierListOwner owner, @NotNull String annotationFQName, boolean successful); + + /** + * Invoked when modules/libraries roots were changed, external annotations files were modified, etc. + */ + void externalAnnotationsChangedDramatically(); + + abstract class Adapter implements ExternalAnnotationsListener { + @Override + public void afterExternalAnnotationChanging(@NotNull PsiModifierListOwner owner, @NotNull String annotationFQName, boolean successful) { + } + + @Override + public void externalAnnotationsChangedDramatically() { + } + } +} diff --git a/java/java-psi-api/src/com/intellij/codeInsight/ExternalAnnotationsManager.java b/java/java-psi-api/src/com/intellij/codeInsight/ExternalAnnotationsManager.java index 749965722155..53ba47f0cca5 100644 --- a/java/java-psi-api/src/com/intellij/codeInsight/ExternalAnnotationsManager.java +++ b/java/java-psi-api/src/com/intellij/codeInsight/ExternalAnnotationsManager.java @@ -24,6 +24,7 @@ import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.NotNullLazyKey; import com.intellij.psi.*; +import com.intellij.util.messages.Topic; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -33,6 +34,8 @@ import java.util.List; public abstract class ExternalAnnotationsManager { @NonNls public static final String ANNOTATIONS_XML = "annotations.xml"; + public static final Topic TOPIC = Topic.create("external annotations", ExternalAnnotationsListener.class); + public enum AnnotationPlace { IN_CODE, EXTERNAL,