package com.chrisfolger.needsmoredojo.intellij.actions;
import com.chrisfolger.needsmoredojo.core.amd.filesystem.DojoModuleFileResolver;
import com.chrisfolger.needsmoredojo.core.amd.objectmodel.cycledetection.CyclicDependencyDetector;
import com.chrisfolger.needsmoredojo.core.amd.objectmodel.cycledetection.DependencyNode;
import com.chrisfolger.needsmoredojo.core.amd.objectmodel.cycledetection.DetectionResult;
import com.chrisfolger.needsmoredojo.core.settings.DojoSettings;
import com.chrisfolger.needsmoredojo.intellij.toolwindows.FindCyclicDependenciesToolWindow;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowAnchor;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.openapi.wm.ToolWindowType;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import org.apache.log4j.Logger;
import javax.swing.*;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* This action runs a task that scans the dependency graph for your sources. It will list cycles in the graph
* in a separate tool window at the bottom of the IDE.
*/
public class FindCyclicDependenciesAction extends JavaScriptAction
{
private Logger logger = Logger.getLogger(FindCyclicDependenciesAction.class);
private void updateToolWindow(int count, final Project project, final CyclicDependencyDetector detector)
{
final int finalCount = count;
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
ToolWindowManager.getInstance(project).unregisterToolWindow("Find Cyclic AMD Dependencies");
ToolWindow window = ToolWindowManager.getInstance(project).registerToolWindow("Find Cyclic AMD Dependencies", true, ToolWindowAnchor.BOTTOM);
window.setTitle("Find Cyclic AMD Dependencies");
window.setDefaultState(ToolWindowAnchor.BOTTOM, ToolWindowType.DOCKED, null);
window.show(null);
window.activate(null);
Map<String, List<String>> incriminatingModules = detector.getIncriminatingModules();
new FindCyclicDependenciesToolWindow().createContent(project, window, incriminatingModules, finalCount);
}
});
}
@Override
protected boolean fileAgnostic()
{
return true;
}
@Override
public void update(AnActionEvent e) {
if(e.getProject() == null)
{
e.getPresentation().setEnabled(false);
return;
}
if(!ServiceManager.getService(e.getProject(), DojoSettings.class).isNeedsMoreDojoEnabled())
{
e.getPresentation().setEnabled(false);
return;
}
else
{
e.getPresentation().setEnabled(true);
}
}
@Override
public void actionPerformed(final AnActionEvent e)
{
if(e.getProject() == null)
{
return;
}
final ProgressManager instance = ProgressManager.getInstance();
instance.runProcessWithProgressSynchronously(new Runnable() {
@Override
public void run() {
try
{
instance.getProgressIndicator().setIndeterminate(true);
final CyclicDependencyDetector detector = new CyclicDependencyDetector();
Collection<VirtualFile> filesToSearch = new DojoModuleFileResolver().getAllDojoProjectSourceFiles(e.getProject());
int count = 0;
for (VirtualFile file : filesToSearch)
{
if (DojoModuleFileResolver.isInDojoSources(file.getPath()))
{
continue;
}
try
{
PsiFile psiFile = PsiManager.getInstance(e.getProject()).findFile(file);
DependencyNode cycle = detector.addDependenciesOfFile(psiFile, psiFile.getProject(), psiFile, null, null, false);
if (cycle != null)
{
DetectionResult cycleDetectionResult = detector.getCycleDetectionResult(cycle);
detector.updateIncriminatingModules(cycleDetectionResult.getDependencies(), cycleDetectionResult.getCyclePath());
count++;
}
}
catch(ProcessCanceledException exception)
{
new Notification("needsmoredojo", "Find Circular Dependencies", "Find Circular Dependencies action was canceled", NotificationType.INFORMATION).notify(e.getProject());
return;
}
catch (Exception ex)
{
logger.error(ex, ex);
}
}
if (count == 0)
{
new Notification("needsmoredojo", "Find Circular Dependencies", "No cycles were found in the dependency graph", NotificationType.INFORMATION).notify(e.getProject());
}
else
{
updateToolWindow(count, e.getProject(), detector);
}
}
catch(ProcessCanceledException exception)
{
new Notification("needsmoredojo", "Find Circular Dependencies", "Find Circular Dependencies action was canceled", NotificationType.INFORMATION).notify(e.getProject());
}
}
}, "Searching for circular dependencies", true, e.getProject());
}
}