blob: 825e72bc98e6f9e3f8048993a8f7165ee46c2875 [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.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInsight.daemon.impl.analysis.FileHighlightingSetting;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightLevelUtil;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightingLevelManager;
import com.intellij.lang.Language;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.EditorBundle;
import com.intellij.openapi.editor.HectorComponentPanel;
import com.intellij.openapi.editor.HectorComponentPanelsProvider;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.profile.codeInspection.ui.ErrorsConfigurable;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.ui.HyperlinkLabel;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.plaf.basic.BasicSliderUI;
import java.awt.*;
import java.lang.ref.WeakReference;
import java.util.*;
import java.util.List;
/**
* User: anna
* Date: Jun 27, 2005
*/
public class HectorComponent extends JPanel {
private static final Logger LOG = Logger.getInstance("com.intellij.openapi.editor.impl.HectorComponent");
private WeakReference<JBPopup> myHectorRef;
private final ArrayList<HectorComponentPanel> myAdditionalPanels;
private final Map<Language, JSlider> mySliders;
private final PsiFile myFile;
private final String myTitle = EditorBundle.message("hector.highlighting.level.title");
public HectorComponent(@NotNull PsiFile file) {
super(new GridBagLayout());
setBorder(BorderFactory.createEmptyBorder(0, 0, 7, 0));
myFile = file;
mySliders = new HashMap<Language, JSlider>();
final Project project = myFile.getProject();
final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
final VirtualFile virtualFile = myFile.getContainingFile().getVirtualFile();
LOG.assertTrue(virtualFile != null);
final boolean notInLibrary =
!fileIndex.isInLibrarySource(virtualFile) && !fileIndex.isInLibraryClasses(virtualFile) || fileIndex.isInContent(virtualFile);
final FileViewProvider viewProvider = myFile.getViewProvider();
List<Language> languages = new ArrayList<Language>(viewProvider.getLanguages());
Collections.sort(languages, PsiUtilBase.LANGUAGE_COMPARATOR);
for (Language language : languages) {
@SuppressWarnings("UseOfObsoleteCollectionType")
final Hashtable<Integer, JComponent> sliderLabels = new Hashtable<Integer, JComponent>();
sliderLabels.put(1, new JLabel(EditorBundle.message("hector.none.slider.label")));
sliderLabels.put(2, new JLabel(EditorBundle.message("hector.syntax.slider.label")));
if (notInLibrary) {
sliderLabels.put(3, new JLabel(EditorBundle.message("hector.inspections.slider.label")));
}
final JSlider slider = new JSlider(SwingConstants.VERTICAL, 1, notInLibrary ? 3 : 2, 1);
if (UIUtil.isUnderGTKLookAndFeel()) {
// default GTK+ slider UI is way too ugly
slider.putClientProperty("Slider.paintThumbArrowShape", true);
slider.setUI(new BasicSliderUI(slider));
}
slider.setLabelTable(sliderLabels);
UIUtil.setSliderIsFilled(slider, true);
slider.setPaintLabels(true);
slider.setSnapToTicks(true);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
int value = slider.getValue();
for (Enumeration<Integer> enumeration = sliderLabels.keys(); enumeration.hasMoreElements();) {
Integer key = enumeration.nextElement();
sliderLabels.get(key).setForeground(key.intValue() <= value ? UIUtil.getLabelForeground() : UIUtil.getLabelDisabledForeground());
}
}
});
final PsiFile psiRoot = viewProvider.getPsi(language);
assert psiRoot != null : "No root in " + viewProvider + " for " + language;
slider.setValue(getValue(HighlightingLevelManager.getInstance(project).shouldHighlight(psiRoot), HighlightingLevelManager.getInstance(project).shouldInspect(
psiRoot)));
mySliders.put(language, slider);
}
GridBagConstraints gc = new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0, 0, GridBagConstraints.NORTHWEST,
GridBagConstraints.NONE, new Insets(0, 5, 0, 0), 0, 0);
JPanel panel = new JPanel(new GridBagLayout());
panel.setBorder(IdeBorderFactory.createTitledBorder(myTitle, false));
final boolean addLabel = mySliders.size() > 1;
if (addLabel) {
layoutVertical(panel);
}
else {
layoutHorizontal(panel);
}
gc.gridx = 0;
gc.gridy = 0;
gc.weighty = 1.0;
gc.fill = GridBagConstraints.BOTH;
add(panel, gc);
gc.gridy = GridBagConstraints.RELATIVE;
gc.weighty = 0;
final HyperlinkLabel configurator = new HyperlinkLabel("Configure inspections");
gc.insets.right = 5;
gc.insets.bottom = 10;
gc.weightx = 0;
gc.fill = GridBagConstraints.NONE;
gc.anchor = GridBagConstraints.EAST;
add(configurator, gc);
configurator.addHyperlinkListener(new HyperlinkListener() {
@Override
public void hyperlinkUpdate(HyperlinkEvent e) {
final JBPopup hector = getOldHector();
if (hector != null) {
hector.cancel();
}
if (!DaemonCodeAnalyzer.getInstance(myFile.getProject()).isHighlightingAvailable(myFile)) return;
final Project project = myFile.getProject();
final ErrorsConfigurable errorsConfigurable = ErrorsConfigurable.SERVICE.createConfigurable(project);
assert errorsConfigurable != null;
ShowSettingsUtil.getInstance().editConfigurable(project, errorsConfigurable);
}
});
gc.anchor = GridBagConstraints.WEST;
gc.weightx = 1.0;
gc.insets.right = 0;
gc.fill = GridBagConstraints.HORIZONTAL;
myAdditionalPanels = new ArrayList<HectorComponentPanel>();
for (HectorComponentPanelsProvider provider : Extensions.getExtensions(HectorComponentPanelsProvider.EP_NAME, project)) {
final HectorComponentPanel componentPanel = provider.createConfigurable(file);
if (componentPanel != null) {
myAdditionalPanels.add(componentPanel);
add(componentPanel.createComponent(), gc);
componentPanel.reset();
}
}
}
@Override
public Dimension getPreferredSize() {
final Dimension preferredSize = super.getPreferredSize();
final int width = 300;
if (preferredSize.width < width){
preferredSize.width = width;
}
return preferredSize;
}
private void layoutHorizontal(final JPanel panel) {
for (JSlider slider : mySliders.values()) {
slider.setOrientation(SwingConstants.HORIZONTAL);
slider.setPreferredSize(new Dimension(200, 40));
panel.add(slider, new GridBagConstraints(0, 1, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
new Insets(5, 0, 5, 0), 0, 0));
}
}
private void layoutVertical(final JPanel panel) {
for (Language language : mySliders.keySet()) {
JSlider slider = mySliders.get(language);
JPanel borderPanel = new JPanel(new BorderLayout());
slider.setPreferredSize(new Dimension(100, 100));
borderPanel.add(new JLabel(language.getID()), BorderLayout.NORTH);
borderPanel.add(slider, BorderLayout.CENTER);
panel.add(borderPanel, new GridBagConstraints(GridBagConstraints.RELATIVE, 1, 1, 1, 0, 1, GridBagConstraints.CENTER, GridBagConstraints.VERTICAL,
new Insets(0, 5, 0, 5), 0, 0));
}
}
public void showComponent(RelativePoint point) {
final JBPopup hector = JBPopupFactory.getInstance().createComponentPopupBuilder(this, this)
.setRequestFocus(true)
.setMovable(true)
.setCancelCallback(new Computable<Boolean>() {
@Override
public Boolean compute() {
for (HectorComponentPanel additionalPanel : myAdditionalPanels) {
if (!additionalPanel.canClose()) {
return Boolean.FALSE;
}
}
onClose();
return Boolean.TRUE;
}
})
.createPopup();
Disposer.register(myFile.getProject(), new Disposable() {
@Override
public void dispose() {
final JBPopup oldHector = getOldHector();
if (oldHector != null && !oldHector.isDisposed()) {
Disposer.dispose(oldHector);
}
Disposer.dispose(hector);
}
});
final JBPopup oldHector = getOldHector();
if (oldHector != null){
oldHector.cancel();
} else {
myHectorRef = new WeakReference<JBPopup>(hector);
hector.show(point);
}
}
@Nullable
private JBPopup getOldHector(){
if (myHectorRef == null) return null;
final JBPopup hector = myHectorRef.get();
if (hector == null || !hector.isVisible()){
myHectorRef = null;
return null;
}
return hector;
}
private void onClose() {
if (isModified()) {
for (HectorComponentPanel panel : myAdditionalPanels) {
try {
panel.apply();
}
catch (ConfigurationException e) {
//shouldn't be
}
}
forceDaemonRestart();
DaemonListeners.getInstance(myFile.getProject()).updateStatusBar();
}
}
private void forceDaemonRestart() {
final FileViewProvider viewProvider = myFile.getViewProvider();
for (Language language : mySliders.keySet()) {
JSlider slider = mySliders.get(language);
PsiElement root = viewProvider.getPsi(language);
assert root != null : "No root in " + viewProvider + " for " + language;
int value = slider.getValue();
if (value == 1) {
HighlightLevelUtil.forceRootHighlighting(root, FileHighlightingSetting.SKIP_HIGHLIGHTING);
}
else if (value == 2) {
HighlightLevelUtil.forceRootHighlighting(root, FileHighlightingSetting.SKIP_INSPECTION);
}
else {
HighlightLevelUtil.forceRootHighlighting(root, FileHighlightingSetting.FORCE_HIGHLIGHTING);
}
}
final DaemonCodeAnalyzer analyzer = DaemonCodeAnalyzer.getInstance(myFile.getProject());
analyzer.restart();
}
private boolean isModified() {
final FileViewProvider viewProvider = myFile.getViewProvider();
for (Language language : mySliders.keySet()) {
JSlider slider = mySliders.get(language);
final PsiFile root = viewProvider.getPsi(language);
HighlightingLevelManager highlightingLevelManager = HighlightingLevelManager.getInstance(myFile.getProject());
if (root != null && getValue(highlightingLevelManager.shouldHighlight(root), highlightingLevelManager.shouldInspect(root)) != slider.getValue()) {
return true;
}
}
for (HectorComponentPanel panel : myAdditionalPanels) {
if (panel.isModified()) {
return true;
}
}
return false;
}
private static int getValue(boolean isSyntaxHighlightingEnabled, boolean isInspectionsHighlightingEnabled) {
if (!isSyntaxHighlightingEnabled && !isInspectionsHighlightingEnabled) {
return 1;
}
if (isSyntaxHighlightingEnabled && !isInspectionsHighlightingEnabled) {
return 2;
}
return 3;
}
}