blob: 760029d689dbf1fa94a6a9c0236efca58b6a767c [file] [log] [blame]
/*
* Copyright 2000-2014 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.daemon.impl;
import com.intellij.ProjectTopics;
import com.intellij.codeHighlighting.Pass;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings;
import com.intellij.codeInsight.hint.TooltipController;
import com.intellij.ide.IdeTooltipManager;
import com.intellij.ide.PowerSaveMode;
import com.intellij.ide.todo.TodoConfiguration;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.ActionManagerEx;
import com.intellij.openapi.actionSystem.ex.AnActionListener;
import com.intellij.openapi.application.*;
import com.intellij.openapi.application.impl.LaterInvocator;
import com.intellij.openapi.command.CommandAdapter;
import com.intellij.openapi.command.CommandEvent;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.command.undo.UndoManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.actionSystem.DocCommandGroupId;
import com.intellij.openapi.editor.colors.EditorColorsListener;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.event.*;
import com.intellij.openapi.editor.ex.EditorEventMulticasterEx;
import com.intellij.openapi.editor.ex.EditorMarkupModel;
import com.intellij.openapi.editor.impl.EditorImpl;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.TextEditor;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectUtil;
import com.intellij.openapi.roots.ModuleRootAdapter;
import com.intellij.openapi.roots.ModuleRootEvent;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.UserDataHolderEx;
import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileAdapter;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.VirtualFilePropertyEvent;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.wm.ex.StatusBarEx;
import com.intellij.openapi.wm.impl.status.TogglePopupHintsPanel;
import com.intellij.packageDependencies.DependencyValidationManager;
import com.intellij.profile.Profile;
import com.intellij.profile.ProfileChangeAdapter;
import com.intellij.profile.codeInspection.InspectionProfileManager;
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiDocumentManagerImpl;
import com.intellij.psi.impl.PsiManagerEx;
import com.intellij.psi.search.scope.packageSet.NamedScopeManager;
import com.intellij.util.messages.MessageBus;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.ui.UIUtil;
import com.intellij.vcsUtil.VcsUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* @author cdr
*/
public class DaemonListeners implements Disposable {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.DaemonListeners");
private final Project myProject;
private final DaemonCodeAnalyzerImpl myDaemonCodeAnalyzer;
@NotNull private final PsiDocumentManager myPsiDocumentManager;
private final FileEditorManager myFileEditorManager;
private final UndoManager myUndoManager;
private final ProjectLevelVcsManager myProjectLevelVcsManager;
private final VcsDirtyScopeManager myVcsDirtyScopeManager;
private final FileStatusManager myFileStatusManager;
@NotNull private final ActionManager myActionManager;
private final TooltipController myTooltipController;
private boolean myEscPressed;
private volatile boolean cutOperationJustHappened;
private final DaemonCodeAnalyzer.DaemonListener myDaemonEventPublisher;
private static final Key<Boolean> DAEMON_INITIALIZED = Key.create("DAEMON_INITIALIZED");
public static DaemonListeners getInstance(Project project) {
return project.getComponent(DaemonListeners.class);
}
public DaemonListeners(@NotNull Project project,
@NotNull DaemonCodeAnalyzerImpl daemonCodeAnalyzer,
@NotNull final EditorTracker editorTracker,
@NotNull EditorFactory editorFactory,
@NotNull PsiDocumentManager psiDocumentManager,
@NotNull CommandProcessor commandProcessor,
@NotNull EditorColorsManager editorColorsManager,
@NotNull final Application application,
@NotNull InspectionProfileManager inspectionProfileManager,
@NotNull InspectionProjectProfileManager inspectionProjectProfileManager,
@NotNull TodoConfiguration todoConfiguration,
@NotNull ActionManagerEx actionManagerEx,
@NotNull VirtualFileManager virtualFileManager,
@NotNull final NamedScopeManager namedScopeManager,
@NotNull final DependencyValidationManager dependencyValidationManager,
@NotNull final FileDocumentManager fileDocumentManager,
@NotNull final PsiManager psiManager,
@NotNull final FileEditorManager fileEditorManager,
@NotNull TooltipController tooltipController,
@NotNull UndoManager undoManager,
@NotNull ProjectLevelVcsManager projectLevelVcsManager,
@NotNull VcsDirtyScopeManager vcsDirtyScopeManager,
@NotNull FileStatusManager fileStatusManager) {
Disposer.register(project, this);
myProject = project;
myDaemonCodeAnalyzer = daemonCodeAnalyzer;
myPsiDocumentManager = psiDocumentManager;
myFileEditorManager = fileEditorManager;
myUndoManager = undoManager;
myProjectLevelVcsManager = projectLevelVcsManager;
myVcsDirtyScopeManager = vcsDirtyScopeManager;
myFileStatusManager = fileStatusManager;
myActionManager = actionManagerEx;
myTooltipController = tooltipController;
boolean replaced = ((UserDataHolderEx)myProject).replace(DAEMON_INITIALIZED, null, Boolean.TRUE);
LOG.assertTrue(replaced, "Daemon listeners already initialized for the project "+myProject);
MessageBus messageBus = myProject.getMessageBus();
myDaemonEventPublisher = messageBus.syncPublisher(DaemonCodeAnalyzer.DAEMON_EVENT_TOPIC);
final MessageBusConnection connection = messageBus.connect();
if (project.isDefault()) return;
EditorEventMulticaster eventMulticaster = editorFactory.getEventMulticaster();
eventMulticaster.addDocumentListener(new DocumentAdapter() {
// clearing highlighters before changing document because change can damage editor highlighters drastically, so we'll clear more than necessary
@Override
public void beforeDocumentChange(final DocumentEvent e) {
if (isUnderIgnoredAction(null)) return;
Document document = e.getDocument();
VirtualFile virtualFile = fileDocumentManager.getFile(document);
Project project = virtualFile == null ? null : ProjectUtil.guessProjectForFile(virtualFile);
if (!worthBothering(document, project)) {
return; //no need to stop daemon if something happened in the console
}
stopDaemon(true, "Document change");
UpdateHighlightersUtil.updateHighlightersByTyping(myProject, e);
}
}, this);
eventMulticaster.addCaretListener(new CaretAdapter() {
@Override
public void caretPositionChanged(CaretEvent e) {
final Editor editor = e.getEditor();
if (!editor.getComponent().isShowing() && !application.isUnitTestMode() ||
!worthBothering(editor.getDocument(), editor.getProject())) {
return; //no need to stop daemon if something happened in the console
}
if (!application.isUnitTestMode()) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
if (!editor.getComponent().isShowing() || myProject.isDisposed()) {
return;
}
myDaemonCodeAnalyzer.hideLastIntentionHint();
}
}, ModalityState.current());
}
}
}, this);
eventMulticaster.addEditorMouseMotionListener(new MyEditorMouseMotionListener(), this);
eventMulticaster.addEditorMouseListener(new MyEditorMouseListener(myTooltipController), this);
EditorTrackerListener editorTrackerListener = new EditorTrackerListener() {
private List<Editor> myActiveEditors = Collections.emptyList();
@Override
public void activeEditorsChanged(@NotNull List<Editor> editors) {
List<Editor> activeEditors = editorTracker.getActiveEditors();
if (myActiveEditors.equals(activeEditors)) {
return;
}
myActiveEditors = activeEditors;
stopDaemon(true, "Active editor change"); // do not stop daemon if idea loses/gains focus
if (ApplicationManager.getApplication().isDispatchThread() && LaterInvocator.isInModalContext()) {
// editor appear in modal context, re-enable the daemon
myDaemonCodeAnalyzer.setUpdateByTimerEnabled(true);
}
for (Editor editor : activeEditors) {
repaintErrorStripeRenderer(editor, myProject);
}
}
};
editorTracker.addEditorTrackerListener(editorTrackerListener, this);
EditorFactoryListener editorFactoryListener = new EditorFactoryListener() {
@Override
public void editorCreated(@NotNull EditorFactoryEvent event) {
Editor editor = event.getEditor();
Document document = editor.getDocument();
Project editorProject = editor.getProject();
// worthBothering() checks for getCachedPsiFile, so call getPsiFile here
PsiFile file = editorProject == null ? null : PsiDocumentManager.getInstance(editorProject).getPsiFile(document);
if (!editor.getComponent().isShowing() || !worthBothering(document, editorProject)) {
LOG.debug("Not worth: " + file);
return;
}
repaintErrorStripeRenderer(editor, myProject);
}
@Override
public void editorReleased(@NotNull EditorFactoryEvent event) {
// mem leak after closing last editor otherwise
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
myDaemonCodeAnalyzer.hideLastIntentionHint();
}
});
}
};
editorFactory.addEditorFactoryListener(editorFactoryListener, this);
PsiDocumentManagerImpl documentManager = (PsiDocumentManagerImpl)psiDocumentManager;
PsiChangeHandler changeHandler = new PsiChangeHandler(myProject, documentManager, editorFactory,connection,
daemonCodeAnalyzer.getFileStatusMap());
Disposer.register(this, changeHandler);
psiManager.addPsiTreeChangeListener(changeHandler, changeHandler);
connection.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootAdapter() {
@Override
public void rootsChanged(ModuleRootEvent event) {
final FileEditor[] editors = fileEditorManager.getSelectedEditors();
if (editors.length == 0) return;
application.invokeLater(new Runnable() {
@Override
public void run() {
if (myProject.isDisposed()) return;
for (FileEditor fileEditor : editors) {
if (fileEditor instanceof TextEditor) {
repaintErrorStripeRenderer(((TextEditor)fileEditor).getEditor(), myProject);
}
}
}
}, ModalityState.stateForComponent(editors[0].getComponent()));
}
});
connection.subscribe(DumbService.DUMB_MODE, new DumbService.DumbModeListener() {
@Override
public void enteredDumbMode() {
stopDaemonAndRestartAllFiles();
}
@Override
public void exitDumbMode() {
stopDaemonAndRestartAllFiles();
}
});
connection.subscribe(PowerSaveMode.TOPIC, new PowerSaveMode.Listener() {
@Override
public void powerSaveStateChanged() {
stopDaemon(true, "Power save mode change");
}
});
commandProcessor.addCommandListener(new MyCommandListener(), this);
application.addApplicationListener(new MyApplicationListener(), this);
editorColorsManager.addEditorColorsListener(new MyEditorColorsListener(), this);
inspectionProfileManager.addProfileChangeListener(new MyProfileChangeListener(), this);
inspectionProjectProfileManager.addProfilesListener(new MyProfileChangeListener(), this);
todoConfiguration.addPropertyChangeListener(new MyTodoListener(), this);
todoConfiguration.colorSettingsChanged();
actionManagerEx.addAnActionListener(new MyAnActionListener(), this);
virtualFileManager.addVirtualFileListener(new VirtualFileAdapter() {
@Override
public void propertyChanged(@NotNull VirtualFilePropertyEvent event) {
String propertyName = event.getPropertyName();
if (VirtualFile.PROP_NAME.equals(propertyName)) {
stopDaemonAndRestartAllFiles();
VirtualFile virtualFile = event.getFile();
PsiFile psiFile = !virtualFile.isValid() ? null : ((PsiManagerEx)psiManager).getFileManager().getCachedPsiFile(virtualFile);
if (psiFile != null && !myDaemonCodeAnalyzer.isHighlightingAvailable(psiFile)) {
Document document = fileDocumentManager.getCachedDocument(virtualFile);
if (document != null) {
// highlight markers no more
//todo clear all highlights regardless the pass id
// Here color scheme required for TextEditorFields, as far as I understand this
// code related to standard file editors, which always use Global color scheme,
// thus we can pass null here.
final EditorColorsScheme editorColorScheme = null;
UpdateHighlightersUtil.setHighlightersToEditor(myProject, document, 0, document.getTextLength(),
Collections.<HighlightInfo>emptyList(),
editorColorScheme,
Pass.UPDATE_ALL);
}
}
}
if (!propertyName.equals(PsiTreeChangeEvent.PROP_WRITABLE)) {
stopDaemon(true, "Virtual file property change");
}
}
}, this);
((EditorEventMulticasterEx)eventMulticaster).addErrorStripeListener(new ErrorStripeHandler(myProject), this);
ModalityStateListener modalityStateListener = new ModalityStateListener() {
@Override
public void beforeModalityStateChanged(boolean entering) {
// before showing dialog we are in non-modal context yet, and before closing dialog we are still in modal context
boolean inModalContext = LaterInvocator.isInModalContext();
stopDaemon(inModalContext, "Modality change");
myDaemonCodeAnalyzer.setUpdateByTimerEnabled(inModalContext);
}
};
LaterInvocator.addModalityStateListener(modalityStateListener,this);
}
static boolean isUnderIgnoredAction(@Nullable Object action) {
return action instanceof DocumentRunnable.IgnoreDocumentRunnable ||
ApplicationManager.getApplication().hasWriteAction(DocumentRunnable.IgnoreDocumentRunnable.class);
}
private boolean worthBothering(final Document document, Project project) {
if (document == null) return true;
if (project != null && project != myProject) return false;
// cached is essential here since we do not want to create PSI file in alien project
PsiFile psiFile = myPsiDocumentManager.getCachedPsiFile(document);
return psiFile != null && psiFile.getOriginalFile() == psiFile;
}
@Override
public void dispose() {
stopDaemonAndRestartAllFiles();
boolean replaced = ((UserDataHolderEx)myProject).replace(DAEMON_INITIALIZED, Boolean.TRUE, Boolean.FALSE);
LOG.assertTrue(replaced, "Daemon listeners already disposed for the project "+myProject);
}
public static boolean canChangeFileSilently(@NotNull PsiFileSystemItem file) {
Project project = file.getProject();
DaemonListeners listeners = getInstance(project);
if (listeners == null) return true;
if (listeners.cutOperationJustHappened) return false;
VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile == null) return false;
if (file instanceof PsiCodeFragment) return true;
if (!ModuleUtilCore.projectContainsFile(project, virtualFile, false)) return false;
Result vcs = listeners.vcsThinksItChanged(virtualFile);
if (vcs == Result.CHANGED) return true;
if (vcs == Result.UNCHANGED) return false;
return listeners.canUndo(virtualFile);
}
private boolean canUndo(@NotNull VirtualFile virtualFile) {
for (FileEditor editor : myFileEditorManager.getEditors(virtualFile)) {
if (myUndoManager.isUndoAvailable(editor)) return true;
}
return false;
}
private enum Result {
CHANGED, UNCHANGED, NOT_SURE
}
private Result vcsThinksItChanged(VirtualFile virtualFile) {
AbstractVcs activeVcs = myProjectLevelVcsManager.getVcsFor(virtualFile);
if (activeVcs == null) return Result.NOT_SURE;
FilePath path = VcsUtil.getFilePath(virtualFile);
boolean vcsIsThinking = !myVcsDirtyScopeManager.whatFilesDirty(Arrays.asList(path)).isEmpty();
if (vcsIsThinking) return Result.NOT_SURE; // do not modify file which is in the process of updating
FileStatus status = myFileStatusManager.getStatus(virtualFile);
if (status == FileStatus.UNKNOWN) return Result.NOT_SURE;
return status == FileStatus.MODIFIED || status == FileStatus.ADDED ? Result.CHANGED : Result.UNCHANGED;
}
private class MyApplicationListener extends ApplicationAdapter {
private boolean myDaemonWasRunning;
@Override
public void beforeWriteActionStart(Object action) {
myDaemonWasRunning = myDaemonCodeAnalyzer.isRunning();
if (!myDaemonWasRunning) return; // we'll restart in writeActionFinished()
stopDaemon(true, "Write action start");
}
@Override
public void writeActionFinished(Object action) {
if (myDaemonWasRunning) {
stopDaemon(true, "Write action finish");
}
}
}
private class MyCommandListener extends CommandAdapter {
private final Object myCutActionName = myActionManager.getAction(IdeActions.ACTION_EDITOR_CUT).getTemplatePresentation().getText();
@Override
public void commandStarted(CommandEvent event) {
Document affectedDocument = extractDocumentFromCommand(event);
if (isUnderIgnoredAction(null)) return;
if (!worthBothering(affectedDocument, event.getProject())) return;
cutOperationJustHappened = myCutActionName.equals(event.getCommandName());
if (!myDaemonCodeAnalyzer.isRunning()) return;
if (LOG.isDebugEnabled()) {
LOG.debug("cancelling code highlighting by command:" + event.getCommand());
}
stopDaemon(false, "Command start");
}
@Nullable
private Document extractDocumentFromCommand(CommandEvent event) {
Document affectedDocument = event.getDocument();
if (affectedDocument != null) return affectedDocument;
Object id = event.getCommandGroupId();
if (id instanceof Document) {
affectedDocument = (Document)id;
}
else if (id instanceof DocCommandGroupId) {
affectedDocument = ((DocCommandGroupId)id).getDocument();
}
return affectedDocument;
}
@Override
public void commandFinished(CommandEvent event) {
Document affectedDocument = extractDocumentFromCommand(event);
if (isUnderIgnoredAction(null)) return;
if (!worthBothering(affectedDocument, event.getProject())) return;
if (myEscPressed) {
myEscPressed = false;
if (affectedDocument != null) {
// prevent Esc key to leave the document in the not-highlighted state
if (!myDaemonCodeAnalyzer.getFileStatusMap().allDirtyScopesAreNull(affectedDocument)) {
stopDaemon(true, "Command finish");
}
}
}
else if (!myDaemonCodeAnalyzer.isRunning()) {
stopDaemon(true, "Command finish");
}
}
}
private class MyEditorColorsListener implements EditorColorsListener {
@Override
public void globalSchemeChange(EditorColorsScheme scheme) {
TodoConfiguration.getInstance().colorSettingsChanged();
stopDaemonAndRestartAllFiles();
}
}
private class MyTodoListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (TodoConfiguration.PROP_TODO_PATTERNS.equals(evt.getPropertyName())) {
stopDaemonAndRestartAllFiles();
}
}
}
private class MyProfileChangeListener extends ProfileChangeAdapter {
@Override
public void profileChanged(Profile profile) {
stopDaemonAndRestartAllFiles();
}
@Override
public void profileActivated(Profile oldProfile, Profile profile) {
stopDaemonAndRestartAllFiles();
}
@Override
public void profilesInitialized() {
inspectionProfilesInitialized();
}
@Override
public void profilesShutdown() {
}
}
private TogglePopupHintsPanel myTogglePopupHintsPanel;
private void inspectionProfilesInitialized() {
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
if (myProject.isDisposed()) return;
StatusBarEx statusBar = (StatusBarEx)WindowManager.getInstance().getStatusBar(myProject);
myTogglePopupHintsPanel = new TogglePopupHintsPanel(myProject);
statusBar.addWidget(myTogglePopupHintsPanel, myProject);
updateStatusBar();
stopDaemonAndRestartAllFiles();
}
});
}
public void updateStatusBar() {
if (myTogglePopupHintsPanel != null) myTogglePopupHintsPanel.updateStatus();
}
private class MyAnActionListener implements AnActionListener {
private final AnAction escapeAction = myActionManager.getAction(IdeActions.ACTION_EDITOR_ESCAPE);
@Override
public void beforeActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) {
myEscPressed = action == escapeAction;
}
@Override
public void afterActionPerformed(final AnAction action, final DataContext dataContext, AnActionEvent event) {
}
@Override
public void beforeEditorTyping(char c, DataContext dataContext) {
Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
//no need to stop daemon if something happened in the console
if (editor != null && !worthBothering(editor.getDocument(), editor.getProject())) {
return;
}
stopDaemon(true, "Editor typing");
}
}
private static class MyEditorMouseListener extends EditorMouseAdapter {
@NotNull
private final TooltipController myTooltipController;
public MyEditorMouseListener(@NotNull TooltipController tooltipController) {
myTooltipController = tooltipController;
}
@Override
public void mouseExited(EditorMouseEvent e) {
if (!myTooltipController.shouldSurvive(e.getMouseEvent())) {
DaemonTooltipUtil.cancelTooltips();
}
}
}
private class MyEditorMouseMotionListener implements EditorMouseMotionListener {
@Override
public void mouseMoved(EditorMouseEvent e) {
Editor editor = e.getEditor();
if (myProject != editor.getProject()) return;
if (editor.getComponent().getClientProperty(EditorImpl.IGNORE_MOUSE_TRACKING) != null) return;
boolean shown = false;
try {
// There is a possible case that cursor is located at soft wrap-introduced virtual space (that is mapped to offset
// of the document symbol just after soft wrap). We don't want to show any tooltips for it then.
VisualPosition visual = editor.xyToVisualPosition(e.getMouseEvent().getPoint());
if (editor.getSoftWrapModel().isInsideOrBeforeSoftWrap(visual)) {
return;
}
LogicalPosition logical = editor.visualToLogicalPosition(visual);
if (e.getArea() == EditorMouseEventArea.EDITING_AREA && !UIUtil.isControlKeyDown(e.getMouseEvent())) {
int offset = editor.logicalPositionToOffset(logical);
if (editor.offsetToLogicalPosition(offset).column != logical.column) return; // we are in virtual space
HighlightInfo info = myDaemonCodeAnalyzer.findHighlightByOffset(editor.getDocument(), offset, false);
if (info == null || info.getDescription() == null) return;
if (IdeTooltipManager.getInstance().hasCurrent()) return;
DaemonTooltipUtil.showInfoTooltip(info, editor, offset);
shown = true;
}
}
finally {
if (!shown && !myTooltipController.shouldSurvive(e.getMouseEvent())) {
DaemonTooltipUtil.cancelTooltips();
}
}
}
@Override
public void mouseDragged(EditorMouseEvent e) {
myTooltipController.cancelTooltips();
}
}
private void stopDaemon(boolean toRestartAlarm, @NonNls String reason) {
myDaemonEventPublisher.daemonCancelEventOccurred();
myDaemonCodeAnalyzer.stopProcess(toRestartAlarm, reason);
}
private void stopDaemonAndRestartAllFiles() {
myDaemonEventPublisher.daemonCancelEventOccurred();
myDaemonCodeAnalyzer.restart();
}
static void repaintErrorStripeRenderer(@NotNull Editor editor, @NotNull Project project) {
ApplicationManager.getApplication().assertIsDispatchThread();
if (!project.isInitialized()) return;
final Document document = editor.getDocument();
final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document);
final EditorMarkupModel markup = (EditorMarkupModel)editor.getMarkupModel();
markup.setErrorPanelPopupHandler(new DaemonEditorPopup(psiFile));
markup.setErrorStripTooltipRendererProvider(new DaemonTooltipRendererProvider(project));
markup.setMinMarkHeight(DaemonCodeAnalyzerSettings.getInstance().ERROR_STRIPE_MARK_MIN_HEIGHT);
TrafficLightRenderer.setOrRefreshErrorStripeRenderer(markup, project, document, psiFile);
}
}