/*
* Copyright 2000-2016 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.ide.todo;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
import com.intellij.openapi.fileEditor.FileEditorManagerListener;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.ui.content.Content;
import org.jetbrains.annotations.NotNull;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
abstract class CurrentFileTodosPanel extends TodoPanel {
CurrentFileTodosPanel(Project project, TodoPanelSettings settings, Content content) {
super(project, settings, true, content);
VirtualFile[] files = FileEditorManager.getInstance(project).getSelectedFiles();
setFile(files.length == 0 ? null : PsiManager.getInstance(myProject).findFile(files[0]));
// It's important to remove this listener. It prevents invocation of setFile method after the tree builder is disposed
project.getMessageBus().connect(this).subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerListener() {
@Override
public void selectionChanged(@NotNull FileEditorManagerEvent e) {
VirtualFile file = e.getNewFile();
final PsiFile psiFile = file != null && file.isValid() ? PsiManager.getInstance(myProject).findFile(file) : null;
// This invokeLater is required. The problem is setFile does a commit to PSI, but setFile is
// invoked inside PSI change event. It causes an Exception like "Changes to PSI are not allowed inside event processing"
DumbService.getInstance(myProject).smartInvokeLater(() -> setFile(psiFile));
}
});
}
private void setFile(PsiFile file) {
// setFile method is invoked in LaterInvocator so PsiManager
// can be already disposed, so we need to check this before using it.
if (myProject == null || PsiManager.getInstance(myProject).isDisposed()) {
return;
}
if (file != null && getSelectedFile() == file) return;
CurrentFileTodosTreeBuilder builder = (CurrentFileTodosTreeBuilder)myTodoTreeBuilder;
builder.setFile(file);
if (myTodoTreeBuilder.isUpdatable()) {
Object selectableElement = builder.getTodoTreeStructure().getFirstSelectableElement();
if (selectableElement != null) {
builder.buildNodeForElement(selectableElement);
DefaultMutableTreeNode node = builder.getNodeForElement(selectableElement);
LOG.assertTrue(node != null);
myTodoTreeBuilder.getTree().getSelectionModel().setSelectionPath(new TreePath(node.getPath()));
}
}
}
}