blob: b4a3502f223a5e9162035ccecdd7e6f8100fddf0 [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.util.xml.highlighting;
import com.intellij.codeInsight.daemon.impl.SeverityRegistrar;
import com.intellij.codeInsight.daemon.impl.TrafficLightRenderer;
import com.intellij.icons.AllIcons;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.util.Alarm;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.xml.DomChangeAdapter;
import com.intellij.util.xml.DomElement;
import com.intellij.util.xml.DomManager;
import com.intellij.util.xml.DomUtil;
import com.intellij.util.xml.ui.CommittablePanel;
import com.intellij.util.xml.ui.Highlightable;
import javax.swing.*;
import java.awt.*;
/**
* User: Sergey.Vasiliev
*/
public class DomElementsErrorPanel extends JPanel implements CommittablePanel, Highlightable {
private static final int ALARM_PERIOD = 241;
private final Project myProject;
private final DomElement[] myDomElements;
private final DomElementsTrafficLightRenderer myErrorStripeRenderer;
private final DomElementAnnotationsManagerImpl myAnnotationsManager;
private final Alarm myAlarm = new Alarm();
public DomElementsErrorPanel(final DomElement... domElements) {
assert domElements.length > 0;
myDomElements = domElements;
final DomManager domManager = domElements[0].getManager();
myProject = domManager.getProject();
myAnnotationsManager = (DomElementAnnotationsManagerImpl)DomElementAnnotationsManager.getInstance(myProject);
setPreferredSize(getDimension());
myErrorStripeRenderer = new DomElementsTrafficLightRenderer(DomUtil.getFile(domElements[0]));
Disposer.register(this, myErrorStripeRenderer);
addUpdateRequest();
domManager.addDomEventListener(new DomChangeAdapter() {
@Override
protected void elementChanged(DomElement element) {
addUpdateRequest();
}
}, this);
}
@Override
public void updateHighlighting() {
updatePanel();
}
private boolean areValid() {
for (final DomElement domElement : myDomElements) {
if (!domElement.isValid()) return false;
}
return true;
}
private void updatePanel() {
myAlarm.cancelAllRequests();
if (!areValid()) return;
repaint();
setToolTipText(myErrorStripeRenderer.getTooltipMessage());
if (!isHighlightingFinished()) {
addUpdateRequest();
}
}
private boolean isHighlightingFinished() {
return !areValid() || myAnnotationsManager.isHighlightingFinished(myDomElements);
}
private void addUpdateRequest() {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
myAlarm.addRequest(new Runnable() {
@Override
public void run() {
if (myProject.isOpen() && !myProject.isDisposed()) {
updatePanel();
}
}
}, ALARM_PERIOD);
}
});
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
myErrorStripeRenderer.paint(this, g, new Rectangle(0, 0, getWidth(), getHeight()));
}
@Override
public void dispose() {
myAlarm.cancelAllRequests();
}
@Override
public JComponent getComponent() {
return this;
}
@Override
public void commit() {
}
@Override
public void reset() {
updatePanel();
}
private static Dimension getDimension() {
return new Dimension(AllIcons.General.ErrorsInProgress.getIconWidth() + 2, AllIcons.General.ErrorsInProgress.getIconHeight() + 2);
}
private class DomElementsTrafficLightRenderer extends TrafficLightRenderer {
public DomElementsTrafficLightRenderer(final PsiFile xmlFile) {
super(xmlFile.getProject(),
PsiDocumentManager.getInstance(xmlFile.getProject()).getDocument(xmlFile), xmlFile);
}
@Override
protected DaemonCodeAnalyzerStatus getDaemonCodeAnalyzerStatus(boolean fillErrorsCount, SeverityRegistrar severityRegistrar) {
final DaemonCodeAnalyzerStatus status = super.getDaemonCodeAnalyzerStatus(fillErrorsCount, severityRegistrar);
if (status != null && isInspectionCompleted()) {
status.errorAnalyzingFinished = true;
}
return status;
}
@Override
protected void fillDaemonCodeAnalyzerErrorsStatus(DaemonCodeAnalyzerStatus status,
boolean fillErrorsCount,
SeverityRegistrar severityRegistrar) {
for (int i = 0; i < status.errorCount.length; i++) {
final HighlightSeverity minSeverity = severityRegistrar.getSeverityByIndex(i);
if (minSeverity == null) {
continue;
}
int sum = 0;
for (DomElement element : myDomElements) {
final DomElementsProblemsHolder holder = myAnnotationsManager.getCachedProblemHolder(element);
sum += (SeverityRegistrar.getSeverityRegistrar(getProject()).compare(minSeverity, HighlightSeverity.WARNING) >= 0 ? holder
.getProblems(element, true, true) : holder.getProblems(element, true, minSeverity)).size();
}
status.errorCount[i] = sum;
}
}
protected boolean isInspectionCompleted() {
return ContainerUtil.and(myDomElements, new Condition<DomElement>() {
@Override
public boolean value(final DomElement element) {
return myAnnotationsManager.getHighlightStatus(element) == DomHighlightStatus.INSPECTIONS_FINISHED;
}
});
}
protected boolean isErrorAnalyzingFinished() {
return ContainerUtil.and(myDomElements, new Condition<DomElement>() {
@Override
public boolean value(final DomElement element) {
return myAnnotationsManager.getHighlightStatus(element).compareTo(DomHighlightStatus.ANNOTATORS_FINISHED) >= 0;
}
});
}
}
}