package org.netbeans.gradle.project; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Collection; import java.util.Objects; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.jtrim.collections.RefLinkedList; import org.jtrim.collections.RefList; import org.jtrim.event.ListenerRef; import org.jtrim.property.PropertySource; import org.netbeans.gradle.project.event.ChangeListenerManager; import org.netbeans.gradle.project.event.GenericChangeListenerManager; import org.netbeans.gradle.project.properties.SwingPropertyChangeForwarder; import org.netbeans.spi.project.ui.ProjectProblemsProvider; public final class ProjectIssueManager { private final Lock mainLock; private final RefList<ProjectIssue> issues; private final ChangeListenerManager changeListeners; private final IssueProperty issuesProperty; private final ProjectProblemsProviderImpl projectProblemsProvider; public ProjectIssueManager() { this.mainLock = new ReentrantLock(); this.issues = new RefLinkedList<>(); this.changeListeners = GenericChangeListenerManager.getSwingNotifier(); this.issuesProperty = new IssueProperty(); this.projectProblemsProvider = new ProjectProblemsProviderImpl(issuesProperty); } public ProjectProblemsProvider asProblemProvider() { return projectProblemsProvider; } public ListenerRef addChangeListener(Runnable listener) { return changeListeners.registerListener(listener); } private void fireChange() { changeListeners.fireEventually(); } public PropertySource<Collection<ProjectIssue>> issues() { return issuesProperty; } public boolean hasIssues() { mainLock.lock(); try { return !issues.isEmpty(); } finally { mainLock.unlock(); } } public Collection<ProjectIssue> getIssues() { mainLock.lock(); try { return new ArrayList<>(issues); } finally { mainLock.unlock(); } } public ProjectIssueRef createIssueRef() { return new ProjectIssueRefImpl(); } private class ProjectIssueRefImpl implements ProjectIssueRef { private RefList.ElementRef<ProjectIssue> infoRef; public ProjectIssueRefImpl() { this.infoRef = null; } @Override public void setInfo(ProjectIssue info) { ProjectIssue prevInfo; mainLock.lock(); try { prevInfo = infoRef != null ? infoRef.getElement() : null; if (info == null) { if (infoRef != null) { infoRef.remove(); infoRef = null; } } else { if (infoRef != null) { infoRef.setElement(info); } else { infoRef = issues.addLastGetReference(info); } } } finally { mainLock.unlock(); } if (!Objects.equals(prevInfo, info)) { fireChange(); } } } private final class IssueProperty implements PropertySource<Collection<ProjectIssue>> { @Override public Collection<ProjectIssue> getValue() { return getIssues(); } @Override public ListenerRef addChangeListener(Runnable listener) { return ProjectIssueManager.this.addChangeListener(listener); } } private static class ProjectProblemsProviderImpl implements ProjectProblemsProvider { private final PropertySource<Collection<ProjectIssue>> informations; private final SwingPropertyChangeForwarder properties; public ProjectProblemsProviderImpl(PropertySource<Collection<ProjectIssue>> informations) { this.informations = informations; SwingPropertyChangeForwarder.Builder propertiesBuilder = new SwingPropertyChangeForwarder.Builder(); propertiesBuilder.addProperty(ProjectProblemsProvider.PROP_PROBLEMS, informations); this.properties = propertiesBuilder.create(); } @Override public void addPropertyChangeListener(PropertyChangeListener listener) { properties.addPropertyChangeListener(listener); } @Override public void removePropertyChangeListener(PropertyChangeListener listener) { properties.removePropertyChangeListener(listener); } @Override public Collection<? extends ProjectProblemsProvider.ProjectProblem> getProblems() { Collection<ProjectIssue> projectInfos = informations.getValue(); Collection<ProjectProblemsProvider.ProjectProblem> result = new ArrayList<>(projectInfos.size()); for (ProjectIssue info: projectInfos) { addProblems(info, result); } return result; } private static ProjectProblemsProvider.ProjectProblem asProblem(ProjectIssue.Entry entry) { switch (entry.getKind()) { case WARNING: return ProjectProblemsProvider.ProjectProblem.createWarning( entry.getSummary(), entry.getDetails()); case ERROR: return ProjectProblemsProvider.ProjectProblem.createError( entry.getSummary(), entry.getDetails()); default: return null; } } private static void addProblems( ProjectIssue info, Collection<? super ProjectProblemsProvider.ProjectProblem> result) { for (ProjectIssue.Entry entry: info.getEntries()) { ProjectProblemsProvider.ProjectProblem problem = asProblem(entry); if (problem != null) { result.add(problem); } } } } }