/* * Copyright 2000-2012 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. */ /* * Created by IntelliJ IDEA. * User: Anna.Kozlova * Date: 31-Jul-2006 * Time: 17:44:39 */ package com.intellij.profile.codeInspection.ui; import com.intellij.codeHighlighting.HighlightDisplayLevel; import com.intellij.codeInsight.daemon.impl.HighlightInfoType; import com.intellij.codeInsight.daemon.impl.SeverityRegistrar; import com.intellij.codeInspection.InspectionManager; import com.intellij.codeInspection.InspectionProfileEntry; import com.intellij.codeInspection.ModifiableModel; import com.intellij.codeInspection.ex.*; import com.intellij.icons.AllIcons; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.colors.CodeInsightColors; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.fileChooser.FileChooser; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.options.BaseConfigurable; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.options.SearchableConfigurable; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.profile.Profile; import com.intellij.profile.ProfileManager; import com.intellij.profile.codeInspection.InspectionProfileManager; import com.intellij.profile.codeInspection.InspectionProjectProfileManager; import com.intellij.ui.ListCellRendererWrapper; import com.intellij.ui.components.JBScrollPane; import com.intellij.util.Alarm; import com.intellij.util.Consumer; import com.intellij.util.SystemProperties; import com.intellij.util.containers.HashMap; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.util.*; import java.util.List; public abstract class InspectionToolsConfigurable extends BaseConfigurable implements ErrorsConfigurable, SearchableConfigurable, Configurable.NoScroll { private final CardLayout myLayout = new CardLayout(); private JPanel myPanel; public static final String ID = "Errors"; public static final String DISPLAY_NAME = "Inspections"; protected JComboBox myProfiles; private final Map myPanels = new HashMap(); private JPanel myWholePanel; private JButton myAddButton; private JButton myDeleteButton; private JButton myImportButton; private JButton myExportButton; private JCheckBox myShareProfileCheckBox; private JButton myCopyButton; private JBScrollPane myJBScrollPane; private final List myDeletedProfiles = new ArrayList(); protected final InspectionProfileManager myProfileManager; protected final InspectionProjectProfileManager myProjectProfileManager; private static final Logger LOG = Logger.getInstance("#" + InspectionToolsConfigurable.class.getName()); private Alarm mySelectionAlarm; public InspectionToolsConfigurable(@NotNull final InspectionProjectProfileManager projectProfileManager, InspectionProfileManager profileManager) { ((InspectionManagerEx)InspectionManager.getInstance(projectProfileManager.getProject())).buildInspectionSearchIndexIfNecessary(); myAddButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { final Set existingProfileNames = myPanels.keySet(); final ModifiableModel model = SingleInspectionProfilePanel.createNewProfile(-1, getSelectedObject(), myWholePanel, "", existingProfileNames, projectProfileManager.getProject()); if (model != null) { addProfile((InspectionProfileImpl)model); myDeletedProfiles.remove(getProfilePrefix(model) + model.getName()); myDeleteButton.setEnabled(true); } } }); myDeleteButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { final InspectionProfileImpl selectedProfile = (InspectionProfileImpl)myProfiles.getSelectedItem(); ((DefaultComboBoxModel)myProfiles.getModel()).removeElement(selectedProfile); myDeletedProfiles.add(getProfilePrefix(selectedProfile) + selectedProfile.getName()); myDeleteButton.setEnabled(isDeleteEnabled(selectedProfile)); } }); final Project project = projectProfileManager.getProject(); myImportButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { final FileChooserDescriptor descriptor = new FileChooserDescriptor(true, false, false, false, false, false) { @Override public boolean isFileSelectable(VirtualFile file) { return file.getFileType().equals(StdFileTypes.XML); } }; descriptor.setDescription("Choose profile file"); FileChooser.chooseFile(descriptor, project, myWholePanel, null, new Consumer() { @Override public void consume(VirtualFile file) { if (file == null) return; InspectionProfileImpl profile = new InspectionProfileImpl("TempProfile", InspectionToolRegistrar.getInstance(), myProfileManager); try { Element rootElement = JDOMUtil.loadDocument(VfsUtilCore.virtualToIoFile(file)).getRootElement(); if (Comparing.strEqual(rootElement.getName(), "component")) {//import right from .idea/inspectProfiles/xxx.xml rootElement = rootElement.getChildren().get(0); } final Set levels = new HashSet(); for (Object o : rootElement.getChildren("inspection_tool")) { final Element inspectElement = (Element)o; levels.add(inspectElement.getAttributeValue("level")); for (Object s : inspectElement.getChildren("scope")) { levels.add(((Element)s).getAttributeValue("level")); } } for (Iterator iterator = levels.iterator(); iterator.hasNext(); ) { String level = iterator.next(); if (myProfileManager.getOwnSeverityRegistrar().getSeverity(level) != null) { iterator.remove(); } } if (!levels.isEmpty()) { if (Messages.showYesNoDialog(myWholePanel, "Undefined severities detected: " + StringUtil.join(levels, ", ") + ". Do you want to create them?", "Warning", Messages.getWarningIcon()) == Messages.YES) { for (String level : levels) { final TextAttributes textAttributes = CodeInsightColors.WARNINGS_ATTRIBUTES.getDefaultAttributes(); HighlightInfoType.HighlightInfoTypeImpl info = new HighlightInfoType.HighlightInfoTypeImpl(new HighlightSeverity(level, 50), com.intellij.openapi.editor.colors .TextAttributesKey.createTextAttributesKey(level)); myProfileManager.getOwnSeverityRegistrar() .registerSeverity(new SeverityRegistrar.SeverityBasedTextAttributes(textAttributes.clone(), info), textAttributes.getErrorStripeColor()); } } } profile.readExternal(rootElement); profile.setLocal(true); profile.initInspectionTools(project); if (getProfilePanel(profile) != null) { if (Messages.showOkCancelDialog(myWholePanel, "Profile with name \'" + profile.getName() + "\' already exists. Do you want to overwrite it?", "Warning", Messages.getInformationIcon()) != Messages.OK) return; } final ModifiableModel model = profile.getModifiableModel(); model.setModified(true); addProfile((InspectionProfileImpl)model); myDeletedProfiles.remove(getProfilePrefix(profile) + profile.getName()); myDeleteButton.setEnabled(true); } catch (InvalidDataException e1) { LOG.error(e1); } catch (JDOMException e1) { LOG.error(e1); } catch (IOException e1) { LOG.error(e1); } } }); } }); myExportButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor(); descriptor.setDescription("Choose directory to store profile file"); FileChooser.chooseFile(descriptor, project, myWholePanel, null, new Consumer() { @Override public void consume(VirtualFile file) { final Element element = new Element("inspections"); try { final SingleInspectionProfilePanel panel = getSelectedPanel(); LOG.assertTrue(panel != null); final InspectionProfileImpl profile = (InspectionProfileImpl)panel.getSelectedProfile(); profile.writeExternal(element); final String filePath = FileUtil.toSystemDependentName(file.getPath()) + File.separator + FileUtil.sanitizeFileName(profile.getName()) + ".xml"; if (new File(filePath).isFile()) { if (Messages .showOkCancelDialog(myWholePanel, "File \'" + filePath + "\' already exist. Do you want to overwrite it?", "Warning", Messages.getQuestionIcon()) != Messages.OK) return; } JDOMUtil.writeDocument(new Document(element), filePath, SystemProperties.getLineSeparator()); } catch (WriteExternalException e1) { LOG.error(e1); } catch (IOException e1) { LOG.error(e1); } } }); } }); myCopyButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { final Set existingProfileNames = myPanels.keySet(); final InspectionProfileImpl model = (InspectionProfileImpl) SingleInspectionProfilePanel.createNewProfile(0, getSelectedObject(), myWholePanel, "", existingProfileNames, project); if (model != null) { final InspectionProfileImpl modifiableModel = (InspectionProfileImpl)model.getModifiableModel(); modifiableModel.setModified(true); addProfile(modifiableModel); myDeletedProfiles.remove(getProfilePrefix(model) + model.getName()); myDeleteButton.setEnabled(true); } } }); myProjectProfileManager = projectProfileManager; myProfileManager = profileManager; myJBScrollPane.setBorder(null); } private void addProfile(InspectionProfileImpl model) { final String modelName = model.getName(); final SingleInspectionProfilePanel panel = createPanel(model, modelName, true); myPanel.add(modelName, panel); if (!myPanels.containsKey(getProfilePrefix(model) + modelName)) { //noinspection unchecked ((DefaultComboBoxModel)myProfiles.getModel()).addElement(model); } putProfile(model, panel); myProfiles.setSelectedItem(model); } @Override public String getDisplayName() { return DISPLAY_NAME; } @Override public String getHelpTopic() { return "preferences.inspections"; } @Override @NotNull public String getId() { return ID; } @Override public Runnable enableSearch(final String option) { return new Runnable(){ @Override public void run() { SingleInspectionProfilePanel panel = getSelectedPanel(); if (panel != null) { panel.setFilter(option); } } }; } @Override public JComponent createComponent() { myProfiles.setRenderer(new ListCellRendererWrapper() { @Override public void customize(final JList list, final Profile value, final int index, final boolean selected, final boolean hasFocus) { final String profileName = value.getName(); setText(profileName); final SingleInspectionProfilePanel panel = getProfilePanel(value); setIcon(panel != null && panel.isProfileShared() ? AllIcons.General.ProjectSettings : AllIcons.General.Settings); } }); myProfiles.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { final InspectionProfileImpl profile = (InspectionProfileImpl)myProfiles.getSelectedItem(); if (profile != null) { myDeleteButton.setEnabled(isDeleteEnabled(profile)); myLayout.show(myPanel, profile.getName()); SingleInspectionProfilePanel panel = getSelectedPanel(); if (panel != null) { myShareProfileCheckBox.setSelected(panel.isProfileShared()); } } } }); myShareProfileCheckBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { final SingleInspectionProfilePanel panel = getSelectedPanel(); LOG.assertTrue(panel != null, "No settings panel for: " + getSelectedObject()); panel.setProfileShared(myShareProfileCheckBox.isSelected()); myProfiles.repaint(); } }); myPanel.setLayout(myLayout); return myWholePanel; } protected abstract InspectionProfileImpl getCurrentProfile(); @Override public boolean isModified() { for (SingleInspectionProfilePanel panel : myPanels.values()) { if (panel.isModified()) return true; } if (getProfiles().size() != myPanels.size()) return true; return !myDeletedProfiles.isEmpty(); } @Override public void apply() throws ConfigurationException { final Map panels = new LinkedHashMap(); for (final String name : myPanels.keySet()) { if (myDeletedProfiles.remove(name)) { final String profileName = getProfilePanel(name).getSelectedProfile().getName(); deleteProfile(profileName); } else { final SingleInspectionProfilePanel panel = getProfilePanel(name); panel.apply(); final ModifiableModel profile = panel.getSelectedProfile(); panels.put(getProfilePrefix(profile) + profile.getName(), panel); } } myPanels.clear(); myPanels.putAll(panels); } private SingleInspectionProfilePanel getProfilePanel(String name) { return myPanels.get(name); } private SingleInspectionProfilePanel getProfilePanel(Profile inspectionProfile) { return getProfilePanel(getProfilePrefix(inspectionProfile) + inspectionProfile.getName()); } private void putProfile(Profile profile, SingleInspectionProfilePanel panel) { myPanels.put(getProfilePrefix(profile) + profile.getName(), panel); } private static String getProfilePrefix(Profile profile) { return (profile.isLocal() ? "L" : "S"); } protected void deleteProfile(String name) { if (myProfileManager.getProfile(name, false) != null) { myProfileManager.deleteProfile(name); } if (myProjectProfileManager.getProfile(name, false) != null) { myProjectProfileManager.deleteProfile(name); } } protected boolean acceptTool(InspectionToolWrapper entry) { return true; } @Override public void reset() { myDeletedProfiles.clear(); myPanels.clear(); final DefaultComboBoxModel model = new DefaultComboBoxModel(); myProfiles.setModel(model); for (Profile profile : getProfiles()) { model.addElement(profile); final String profileName = profile.getName(); final SingleInspectionProfilePanel panel = createPanel((InspectionProfileImpl)profile, profileName, false); putProfile(profile, panel); myPanel.add(profileName, panel); } final InspectionProfileImpl inspectionProfile = getCurrentProfile(); myProfiles.setSelectedItem(inspectionProfile); myLayout.show(myPanel, inspectionProfile.getName()); myDeleteButton.setEnabled(isDeleteEnabled(inspectionProfile)); final SingleInspectionProfilePanel panel = getSelectedPanel(); if (panel != null) { panel.setVisible(true);//make sure that UI was initialized mySelectionAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (mySelectionAlarm != null) { mySelectionAlarm.addRequest(new Runnable() { @Override public void run() { panel.updateSelection(); } }, 200); } } }); myShareProfileCheckBox.setSelected(panel.isProfileShared()); } } private SingleInspectionProfilePanel createPanel(InspectionProfileImpl profile, String profileName, boolean model) { return new SingleInspectionProfilePanel(myProjectProfileManager, profileName, model ? profile : profile.getModifiableModel()) { @Override protected boolean accept(InspectionToolWrapper entry) { return super.accept(entry) && InspectionToolsConfigurable.this.acceptTool(entry); } }; } private boolean isDeleteEnabled(@NotNull InspectionProfileImpl inspectionProfile) { final ProfileManager profileManager = inspectionProfile.getProfileManager(); boolean projectProfileFound = false; boolean ideProfileFound = false; final ComboBoxModel model = myProfiles.getModel(); for (int i = 0; i < model.getSize(); i++) { Profile profile = (Profile)model.getElementAt(i); if (inspectionProfile == profile) continue; final boolean isProjectProfile = profile.getProfileManager() == myProjectProfileManager; projectProfileFound |= isProjectProfile; ideProfileFound |= !isProjectProfile; if (ideProfileFound && projectProfileFound) break; } return profileManager == myProjectProfileManager ? projectProfileFound : ideProfileFound; } protected Collection getProfiles() { final Collection result = new ArrayList(); result.addAll(new TreeSet(myProfileManager.getProfiles())); result.addAll(myProjectProfileManager.getProfiles()); return result; } @Override public void disposeUIResources() { for (SingleInspectionProfilePanel panel : myPanels.values()) { panel.disposeUI(); } myPanels.clear(); if (mySelectionAlarm != null) { Disposer.dispose(mySelectionAlarm); mySelectionAlarm = null; } } @Override public void selectProfile(String name) { for (int i = 0; i < myProfiles.getItemCount(); i++) { if (Comparing.strEqual(((InspectionProfileImpl)myProfiles.getItemAt(i)).getName(), name)) { myProfiles.setSelectedIndex(i); break; } } } @Override public void selectInspectionTool(String selectedToolShortName) { final InspectionProfileImpl inspectionProfile = getSelectedObject(); assert inspectionProfile != null : configuredProfiles(); final SingleInspectionProfilePanel panel = getProfilePanel(inspectionProfile); LOG.assertTrue(panel != null, "No settings panel for: " + inspectionProfile + "; " + configuredProfiles()); panel.selectInspectionTool(selectedToolShortName); } protected SingleInspectionProfilePanel getSelectedPanel() { final InspectionProfileImpl inspectionProfile = getSelectedObject(); assert inspectionProfile != null : configuredProfiles(); return getProfilePanel(inspectionProfile); } private String configuredProfiles() { return "configured profiles: " + StringUtil.join(myPanels.keySet(), ", "); } protected Set getKnownNames() { return myPanels.keySet(); } @Override public InspectionProfileImpl getSelectedObject() { return (InspectionProfileImpl)myProfiles.getSelectedItem(); } @Override public JComponent getPreferredFocusedComponent() { final InspectionProfileImpl inspectionProfile = getSelectedObject(); assert inspectionProfile != null : configuredProfiles(); return getProfilePanel(inspectionProfile).getPreferredFocusedComponent(); } }