Package org.twodividedbyzero.idea.findbugs.gui.preferences

Source Code of org.twodividedbyzero.idea.findbugs.gui.preferences.PluginConfiguration$PluginComponent$PluginEditorPane

/*
* Copyright 2008-2014 Andre Pfeiler
*
* This file is part of FindBugs-IDEA.
*
* FindBugs-IDEA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FindBugs-IDEA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with FindBugs-IDEA.  If not, see <http://www.gnu.org/licenses/>.
*/

package org.twodividedbyzero.idea.findbugs.gui.preferences;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.ui.JBColor;
import edu.umd.cs.findbugs.BugCollection;
import edu.umd.cs.findbugs.Plugin;
import edu.umd.cs.findbugs.Project;
import info.clearthought.layout.TableLayout;
import info.clearthought.layout.TableLayoutConstants;
import org.jetbrains.annotations.Nullable;
import org.twodividedbyzero.idea.findbugs.common.util.FindBugsCustomPluginUtil;
import org.twodividedbyzero.idea.findbugs.common.util.FindBugsUtil;
import org.twodividedbyzero.idea.findbugs.common.util.GuiUtil;
import org.twodividedbyzero.idea.findbugs.gui.common.CustomLineBorder;
import org.twodividedbyzero.idea.findbugs.gui.common.ExtensionFileFilter;
import org.twodividedbyzero.idea.findbugs.gui.common.ScrollPaneFacade;
import org.twodividedbyzero.idea.findbugs.gui.preferences.BrowseAction.BrowseActionCallback;
import org.twodividedbyzero.idea.findbugs.gui.toolwindow.view.ToolWindowPanel;
import org.twodividedbyzero.idea.findbugs.plugins.AbstractPluginLoader;
import org.twodividedbyzero.idea.findbugs.preferences.FindBugsPreferences;
import org.twodividedbyzero.idea.findbugs.preferences.PersistencePreferencesBean;
import org.twodividedbyzero.idea.findbugs.resources.GuiResources;

import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JPanel;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.text.html.HTMLEditorKit;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.List;


/**
* $Date: 2014-07-01 17:54:15 -0500 (Tue, 01 Jul 2014) $
*
* @author Andre Pfeiler<andrepdo@dev.java.net>
* @version $Revision: 326 $
* @since 0.9.97
*/
@SuppressWarnings({"AnonymousInnerClass", "HardcodedLineSeparator"})
public class PluginConfiguration implements ConfigurationPage {

  private static final Logger LOGGER = Logger.getInstance(PluginConfiguration.class.getName());

  /**
   * False because:
   * - Its not yet possible to clear/eject current bug collection
   * - Needs some UI visualization to make clear plugins states comes from bug collection
   */
  private static final boolean RESPECT_PROJECT_PLUGIN_STATE = false;

  private static final Color PLUGIN_DESCRIPTION_BG_COLOR = UIManager.getColor("Tree.textBackground");

  private final FindBugsPreferences _preferences;
  private final ConfigurationPanel _parent;
  private Component _component;
  private JPanel _pluginsPanel;
  private JPanel _pluginComponentPanel;


  public PluginConfiguration(final ConfigurationPanel parent, final FindBugsPreferences preferences) {
    //noinspection AssignmentToCollectionOrArrayFieldFromParameter
    _preferences = preferences;
    _parent = parent;
  }


  public Component getComponent() {
    if (_component == null) {
      final double border = 5;
      final double[][] size = {{border, TableLayoutConstants.FILL, border}, // Columns
                   {border, TableLayoutConstants.PREFERRED, border}};// Rows
      final TableLayout tbl = new TableLayout(size);

      final JComponent mainPanel = new JPanel(tbl);
      mainPanel.setBorder(BorderFactory.createCompoundBorder(new EmptyBorder(5, 5, 5, 5), BorderFactory.createTitledBorder("Installed Plugins")));
      _component = mainPanel;
      mainPanel.add(getPluginPanel(), "1, 1, 1, 1");

    }
    //updatePreferences();
    return _component;
  }


  public void updatePreferences() {
    rebuildPluginComponents();
  }


  @edu.umd.cs.findbugs.annotations.SuppressFBWarnings({"SIC_INNER_SHOULD_BE_STATIC_ANON"})
  @SuppressWarnings({"ObjectAllocationInLoop"})
  private void rebuildPluginComponents() {
    if (_pluginComponentPanel == null) {
      return;
    }
    _pluginComponentPanel.removeAll();

    final PluginLoaderImpl pluginLoader = new PluginLoaderImpl(getCurrentFbProject());
    pluginLoader.load(_preferences.getPlugins(), _preferences.getDisabledUserPluginIds(), _preferences.getEnabledBundledPluginIds(), _preferences.getDisabledBundledPluginIds());
    pluginLoader.showErrorBalloonIfNecessary(_parent.getProject()); // LATER: check can we display errors in the bottom of the settings dialog?

    final JPanel pluginComponent = pluginLoader.getLastPluginComponent();
    if (pluginComponent != null) {
      SwingUtilities.invokeLater(new Runnable() {
        public void run() {
          pluginComponent.scrollRectToVisible(new Rectangle(0, 0));
        }
      });
    }
  }


  JPanel getPluginPanel() {
    if (_pluginsPanel == null) {

      final double border = 5;
      final double colsGap = 10;
      final double[][] size = {{border, TableLayoutConstants.PREFERRED, colsGap, TableLayoutConstants.PREFERRED, border}, // Columns
                   {border, TableLayoutConstants.FILL, border}};// Rows
      final TableLayout tbl = new TableLayout(size);
      _pluginsPanel = new JPanel(tbl);

      _pluginComponentPanel = new JPanel();
      _pluginComponentPanel.setLayout(new BoxLayout(_pluginComponentPanel, BoxLayout.Y_AXIS));
      rebuildPluginComponents();

      final Component scrollPane = ScrollPaneFacade.createScrollPane(_pluginComponentPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
      _pluginsPanel.add(scrollPane, "1, 1, 1, 1"); // col ,row, col, row


      final double rowsGap = 5;
      final double[][] bPanelSize = {{border, TableLayoutConstants.PREFERRED}, // Columns
                       {border, TableLayoutConstants.PREFERRED, rowsGap, TableLayoutConstants.PREFERRED, border}};// Rows
      final TableLayout tableLayout = new TableLayout(bPanelSize);

      final Container buttonPanel = new JPanel(tableLayout);
      _pluginsPanel.add(buttonPanel, "3, 1, 3, 1");

      final AbstractButton addButton = new JButton();
      final Action action = new BrowseAction(_parent, "Add Plugin...", new ExtensionFileFilter(FindBugsUtil.PLUGINS_EXTENSIONS_SET), new BrowseActionCallback() {
        public void addSelection(final File selectedFile) {
          doAddPlugin(selectedFile);
        }
      });
      addButton.setAction(action);
      buttonPanel.add(addButton, "1, 1, 1, 1");

    }

    return _pluginsPanel;
  }


  private void doAddPlugin(final File selectedFile) {
    try {
      // TODO CUSTOM_PLUGIN: check what happen when a plugin with same pluginId is already loaded ?
      final Plugin plugin = FindBugsCustomPluginUtil.loadTemporary(selectedFile);
      if (plugin == null) {
        Messages.showErrorDialog(_parent, "Can not load plugin " + selectedFile.getPath(), "Plugin Loading");
        return;
      }
      try {
        final int answer = Messages.showYesNoDialog(_parent, "Add plugin '" + plugin.getPluginId() + "'?", "Add Plugin", null);
        if (answer == Messages.YES) {
          _preferences.addUserPlugin(FindBugsCustomPluginUtil.getAsString(plugin), plugin.getPluginId(), true);
          updatePreferences();
          _preferences.setModified(true);
        }
      } finally {
        FindBugsCustomPluginUtil.unload(plugin);
      }
    } catch (final Throwable e) {
      //noinspection DialogTitleCapitalization
      Messages.showErrorDialog(_parent, "Error loading " + selectedFile.getPath() + ":\n\n" + e.getClass().getSimpleName() + ": " + e.getMessage(), "Error loading plugin");
    }
  }


  @Nullable
  private Project getCurrentFbProject() {
    final ToolWindowPanel panel = _parent.getFindBugsPlugin().getToolWindowPanel();
    if (panel == null) {
      return null;
    }
    final BugCollection bugCollection = panel.getBugCollection();
    if (bugCollection == null) {
      return null;
    }
    return bugCollection.getProject();
  }


  public void setEnabled(final boolean enabled) {
    getPluginPanel().setEnabled(enabled);
  }


  public boolean showInModulePreferences() {
    return false;
  }


  public boolean isAdvancedConfig() {
    return false;
  }


  public String getTitle() {
    return "Plugins";
  }


  public void filter(final String filter) {
    // TODO support search
  }


  public void importPreferences(final com.intellij.openapi.project.Project project, final PersistencePreferencesBean prefs, final ImportCallback callback) {
    final List<String> invalid = FindBugsPreferences.collectInvalidPlugins(prefs.getPlugins());
    if (invalid.isEmpty()) {
      callback.validated(prefs);
    } else {
      showImportDialog(project, prefs, callback, invalid);
    }
  }


  private void showImportDialog(final com.intellij.openapi.project.Project project, final PersistencePreferencesBean prefs, final ImportCallback callback, final List<String> invalidPlugins) {
    final ImportPluginsDialog dialog = new ImportPluginsDialog(project, prefs, invalidPlugins);
    dialog.setModal(true);
    dialog.pack();
    dialog.show();
    if(DialogWrapper.OK_EXIT_CODE == dialog.getExitCode()) {
      prefs.getPlugins().clear();
      prefs.getPlugins().addAll(dialog.getPlugins());
      callback.validated(prefs);
    } // else do not import
  }


  private class PluginLoaderImpl extends AbstractPluginLoader {

    private Project _currentProject;
    private JPanel _lastPluginComponent;


    protected PluginLoaderImpl(final Project currentProject) {
      super(true);
      _currentProject = currentProject;
    }


    @Override
    protected void seenCorePlugin(final Plugin plugin) {
      seenPlugin(plugin, false);
    }


    @Override
    protected void seenBundledPlugin(final Plugin plugin) {
      seenPlugin(plugin, false);
    }


    @Override
    protected void seenUserPlugin(final Plugin plugin) {
      seenPlugin(plugin, true);
    }


    private void seenPlugin(final Plugin plugin, final boolean userPlugin) {
      final PluginComponent pluginPanel = new PluginComponent(_currentProject, plugin, userPlugin, _preferences);
      _lastPluginComponent = pluginPanel.getComponent();
      _pluginComponentPanel.add(_lastPluginComponent);
    }


    public JPanel getLastPluginComponent() {
      return _lastPluginComponent;
    }
  }


  private static class PluginComponent {

    private JPanel _component;
    private final FindBugsPreferences _preferences;
    private static final Border SELECTION_BORDER = BorderFactory.createLineBorder(GuiResources.HIGHLIGHT_COLOR_DARKER);


    private PluginComponent(@Nullable final Project currentProject, final Plugin plugin, final boolean userPlugin, final FindBugsPreferences preferences) {
      /**
       * Do not hold reference to currentProject nor plugin
       */
      _preferences = preferences;
      init(currentProject, plugin, userPlugin);
    }


    void init(@Nullable final Project currentProject, final Plugin plugin, final boolean userPlugin) {
      final double border = 5;
      final double[][] size = {{border, TableLayoutConstants.PREFERRED, 5, TableLayoutConstants.FILL, border}, // Columns
                   {border, TableLayoutConstants.PREFERRED, border}};// Rows
      final TableLayout tbl = new TableLayout(size);
      _component = new JPanel(tbl);
      _component.setBorder(new CustomLineBorder(JBColor.GRAY, 0, 0, 1, 0));
      _component.setBackground(PLUGIN_DESCRIPTION_BG_COLOR);

      String text = plugin.getShortDescription();
      final String pluginId = plugin.getPluginId();
      if (text == null) {
        text = pluginId;
      }

      final String pluginUrl = FindBugsCustomPluginUtil.getAsString(plugin);
      final boolean enabled = isEnabled(currentProject, plugin);
      final AbstractButton checkbox = new JCheckBox();
      checkbox.setEnabled(enabled);
      checkbox.setBackground(PLUGIN_DESCRIPTION_BG_COLOR);
      _component.add(checkbox,"1, 1, 1, 1, L, T");

      final String longText = plugin.getDetailedDescription();
      if (longText != null) {
        checkbox.setToolTipText("<html>" + longText + "</html>");
      }
      checkbox.setSelected(isSelected(currentProject, plugin, userPlugin));
      checkbox.addActionListener(new ActionListener() {
        public void actionPerformed(final ActionEvent e) {
          if (checkbox.isSelected()) {
            if (userPlugin) {
              _preferences.addUserPlugin(pluginUrl, pluginId, true);
            } else {
              _preferences.addBundledPlugin(pluginId, true);
            }
          } else {
            if (userPlugin) {
              final String[] options = {
                  "Disable",
                  "Remove",
                  "Cancel"
              };
              final int answer = Messages.showDialog(checkbox, "Would you like to disable or remove the plugin?", "Disable or Remove", options, 0, Messages.getQuestionIcon());
              if (0 == answer) {
                _preferences.addUserPlugin(pluginUrl, pluginId, false);
              } else if (1 == answer) {
                _preferences.removeUserPlugin(pluginUrl);
              } else {
                // cancel ; restore
                checkbox.setSelected(true);
              }
            } else {
              _preferences.addBundledPlugin(pluginId, false);
            }
          }
        }
      });

      final JEditorPane editorPane = new PluginEditorPane();
      editorPane.setEditable(false);
      editorPane.setEditorKit(new HTMLEditorKit());
      editorPane.setFocusable(false);
      editorPane.setContentType("text/html");

      final String website = plugin.getWebsite();
      final StringBuilder html = new StringBuilder("<html><body width='300px'>");
      html.append("<p><b>").append(text).append("</b> <font style='color:gray; font-size: 8px'>(").append(pluginId).append(")</font> </p>");
      html.append("<p><font style='color: gray; font-weight: normal; font-style:italic'>");
      html.append(pluginUrl);
      html.append("</font>");
      html.append(longText);
      html.append("</p>");

      if (website != null && !website.isEmpty()) {
        html.append("<br><p>");
        html.append("<font style='font-weight: bold; color:gray; font-size: 8px'>Website: ").append(website).append("</font>");
        html.append("</p>");
      }
      html.append("</html></body>");

      editorPane.setText(html.toString());
      _component.add(editorPane, "3, 1, 3, 1");

      _component.addMouseListener(new PluginComponentMouseAdapter(editorPane, checkbox));
      editorPane.addMouseListener(new PluginComponentMouseAdapter(editorPane, checkbox));
    }


    JPanel getComponent() {
      return _component;
    }


    @SuppressWarnings({"PointlessBooleanExpression", "SimplifiableIfStatement"})
    static boolean isEnabled(@Nullable final Project project, final Plugin plugin) {
      if (plugin.isCorePlugin()) {
        return false;
      }
      if (project == null || !RESPECT_PROJECT_PLUGIN_STATE) {
        return !plugin.cannotDisable();
      }
      return false;
    }


    @SuppressWarnings("PointlessBooleanExpression")
    boolean isSelected(@Nullable final Project project, final Plugin plugin, final boolean userPlugin) {
      if (plugin.isCorePlugin()) {
        return true;
      }
      if (project == null || !RESPECT_PROJECT_PLUGIN_STATE) {
        return _preferences.isPluginEnabled(plugin.getPluginId(), userPlugin);
      }
      final Boolean pluginStatus = project.getPluginStatus(plugin);
      return pluginStatus != null && pluginStatus; // need tristate checkbox for better visual state representation
    }


    private static class PluginEditorPane extends JEditorPane {

      @Override
      protected void paintComponent(final Graphics g) {
        GuiUtil.configureGraphics(g);
        super.paintComponent(g);
      }
    }

    private class PluginComponentMouseAdapter extends MouseAdapter {

      private final JEditorPane _editorPane;
      private final AbstractButton _checkbox;


      private PluginComponentMouseAdapter(final JEditorPane editorPane, final AbstractButton checkbox) {
        _editorPane = editorPane;
        _checkbox = checkbox;
      }


      @Override
      public void mouseReleased(final MouseEvent e) {
        _component.setBackground(GuiResources.HIGHLIGHT_COLOR_LIGHTER);
        //_component.setBorder(SELECTION_BORDER);
        _editorPane.setBackground(GuiResources.HIGHLIGHT_COLOR_LIGHTER);
        _checkbox.setBackground(GuiResources.HIGHLIGHT_COLOR_LIGHTER);
      }


      @Override
      public void mouseEntered(final MouseEvent e) {
        _component.setBackground(GuiResources.HIGHLIGHT_COLOR_LIGHTER);
        _editorPane.setBackground(GuiResources.HIGHLIGHT_COLOR_LIGHTER);
        _checkbox.setBackground(GuiResources.HIGHLIGHT_COLOR_LIGHTER);
      }


      @Override
      public void mouseExited(final MouseEvent e) {
        _component.setBackground(PLUGIN_DESCRIPTION_BG_COLOR);
        _editorPane.setBackground(PLUGIN_DESCRIPTION_BG_COLOR);
        _checkbox.setBackground(PLUGIN_DESCRIPTION_BG_COLOR);
      }
    }
  }


  public interface ImportCallback {
    void validated(PersistencePreferencesBean prefs);
  }
}
TOP

Related Classes of org.twodividedbyzero.idea.findbugs.gui.preferences.PluginConfiguration$PluginComponent$PluginEditorPane

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.