diff --git a/platform/util/src/com/intellij/ui/CheckBoxList.java b/platform/util/src/com/intellij/ui/CheckBoxList.java
new file mode 100644
index 000000000000..9570eb4abc13
--- /dev/null
+++ b/platform/util/src/com/intellij/ui/CheckBoxList.java
@@ -0,0 +1,91 @@
+package com.intellij.ui;
+
+import javax.swing.*;
+import javax.swing.border.Border;
+import javax.swing.border.EmptyBorder;
+import javax.swing.plaf.basic.BasicRadioButtonUI;
+import java.awt.*;
+import java.awt.event.*;
+
+/**
+ * @author oleg
+ */
+public class CheckBoxList extends JList {
+ private static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
+ private static final int DEFAULT_CHECK_BOX_WIDTH = 20;
+
+ public CheckBoxList(final ListModel dataModel, final CheckBoxListListener checkBoxListListener) {
+ super(dataModel);
+ setCellRenderer(new CellRenderer());
+ setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ setBorder(BorderFactory.createEtchedBorder());
+ addKeyListener(new KeyAdapter() {
+ @Override
+ public void keyTyped(KeyEvent e) {
+ if (e.getKeyChar() == ' ') {
+ int index = CheckBoxList.this.getSelectedIndex();
+
+ if (index >= 0) {
+ JCheckBox checkbox = (JCheckBox)getModel().getElementAt(index);
+ setSelected(checkbox, index, checkBoxListListener);
+ }
+ }
+ }
+ });
+ addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ if (isEnabled()) {
+ int index = locationToIndex(e.getPoint());
+
+ if (index != -1) {
+ JCheckBox checkbox = (JCheckBox)getModel().getElementAt(index);
+ int iconArea;
+ try {
+ iconArea = ((BasicRadioButtonUI)checkbox.getUI()).getDefaultIcon().getIconWidth();
+ }
+ catch (ClassCastException c) {
+ iconArea = DEFAULT_CHECK_BOX_WIDTH;
+ }
+ if (e.getX() < iconArea) {
+ setSelected(checkbox, index, checkBoxListListener);
+ }
+ }
+ }
+ }
+ });
+ }
+
+ private void setSelected(JCheckBox checkbox, int index, CheckBoxListListener checkBoxListListener) {
+ boolean value = !checkbox.isSelected();
+ checkbox.setSelected(value);
+ repaint();
+ checkBoxListListener.checkBoxSelectionChanged(index, value);
+ }
+
+ private class CellRenderer implements ListCellRenderer {
+ public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+ JCheckBox checkbox = (JCheckBox)value;
+ checkbox.setBackground(getBackgound(isSelected, checkbox));
+ checkbox.setForeground(getForeGround(isSelected, checkbox));
+ checkbox.setEnabled(isEnabled());
+ checkbox.setFont(getFont(checkbox));
+ checkbox.setFocusPainted(false);
+ checkbox.setBorderPainted(true);
+ checkbox.setBorder(isSelected ? UIManager.getBorder("List.focusCellHighlightBorder") : noFocusBorder);
+ return checkbox;
+ }
+ }
+
+ protected Font getFont(final JCheckBox checkbox) {
+ return getFont();
+ }
+
+ protected Color getBackgound(final boolean isSelected, final JCheckBox checkbox) {
+ return isSelected ? getSelectionBackground() : getBackground();
+ }
+
+ protected Color getForeGround(final boolean isSelected, final JCheckBox checkbox) {
+ return isSelected ? getSelectionForeground() : getForeground();
+ }
+
+}
diff --git a/platform/util/src/com/intellij/ui/CheckBoxListListener.java b/platform/util/src/com/intellij/ui/CheckBoxListListener.java
new file mode 100644
index 000000000000..80e12a2566c3
--- /dev/null
+++ b/platform/util/src/com/intellij/ui/CheckBoxListListener.java
@@ -0,0 +1,8 @@
+package com.intellij.ui;
+
+/**
+ * @author oleg
+ */
+public interface CheckBoxListListener {
+ void checkBoxSelectionChanged(int index, boolean value);
+}
diff --git a/platform/util/src/com/intellij/ui/OptionalChooserComponent.form b/platform/util/src/com/intellij/ui/OptionalChooserComponent.form
new file mode 100644
index 000000000000..8bebb6b2da4d
--- /dev/null
+++ b/platform/util/src/com/intellij/ui/OptionalChooserComponent.form
@@ -0,0 +1,28 @@
+
+
diff --git a/platform/util/src/com/intellij/ui/OptionalChooserComponent.java b/platform/util/src/com/intellij/ui/OptionalChooserComponent.java
new file mode 100644
index 000000000000..67e294ed1503
--- /dev/null
+++ b/platform/util/src/com/intellij/ui/OptionalChooserComponent.java
@@ -0,0 +1,69 @@
+package com.intellij.ui;
+
+import com.intellij.openapi.util.Pair;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author oleg
+ * This component represents a list of checkboxes.
+ */
+public abstract class OptionalChooserComponent implements CheckBoxListListener {
+ private JPanel myContentPane;
+ private CheckBoxList myList;
+ private DefaultListModel myListModel;
+ private List> myInitialList;
+ private ArrayList> myWorkingList;
+
+ public OptionalChooserComponent(@NotNull final List> list) {
+ myInitialList = list;
+ myWorkingList = new ArrayList>(myInitialList);
+
+ // fill list
+ reset();
+ }
+
+ public JPanel getContentPane() {
+ return myContentPane;
+ }
+
+ public void checkBoxSelectionChanged(int index, boolean value) {
+ final Pair pair = myWorkingList.remove(index);
+ myWorkingList.add(index, Pair.create(pair.first, value));
+ }
+
+ private void createUIComponents() {
+ myListModel = new DefaultListModel();
+ myList = new CheckBoxList(myListModel, this);
+ }
+
+ public void reset() {
+ myWorkingList = new ArrayList>(myInitialList);
+ update();
+ }
+
+ public abstract JCheckBox createCheckBox(final String path, final boolean checked);
+
+ public boolean isModified() {
+ return !myWorkingList.equals(myInitialList);
+ }
+
+ public ArrayList> getValue() {
+ return myWorkingList;
+ }
+
+ public void apply() {
+ myInitialList.clear();
+ myInitialList.addAll(myWorkingList);
+ }
+
+ public void update() {
+ myListModel.clear();
+ for (Pair pair : myWorkingList) {
+ myListModel.addElement(createCheckBox(pair.first, pair.second));
+ }
+ }
+}
diff --git a/platform/util/src/com/intellij/ui/PathsChooserComponent.form b/platform/util/src/com/intellij/ui/PathsChooserComponent.form
new file mode 100644
index 000000000000..24a5f47f4b65
--- /dev/null
+++ b/platform/util/src/com/intellij/ui/PathsChooserComponent.form
@@ -0,0 +1,49 @@
+
+
diff --git a/platform/util/src/com/intellij/ui/PathsChooserComponent.java b/platform/util/src/com/intellij/ui/PathsChooserComponent.java
new file mode 100644
index 000000000000..d74b34e3c035
--- /dev/null
+++ b/platform/util/src/com/intellij/ui/PathsChooserComponent.java
@@ -0,0 +1,101 @@
+package com.intellij.ui;
+
+import com.intellij.openapi.fileChooser.FileChooserDescriptor;
+import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
+import com.intellij.openapi.fileChooser.FileChooserDialog;
+import com.intellij.openapi.fileChooser.FileChooserFactory;
+import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author oleg
+ * This component is used to configure list of folders with add/remove buttons.
+ */
+public class PathsChooserComponent {
+ private JPanel myContentPane;
+ private JList myList;
+ private JButton myAddButton;
+ private JButton myRemoveButton;
+ private DefaultListModel myListModel;
+
+ private List myWorkingCollection;
+ private List myInitialCollection;
+
+ public PathsChooserComponent(@NotNull final List collection, @NotNull final PathProcessor processor) {
+ myInitialCollection = collection;
+ myWorkingCollection = new ArrayList(myInitialCollection);
+ myListModel = new DefaultListModel();
+ myList.setModel(myListModel);
+
+ // fill list
+ reset();
+
+ // listeners
+ myAddButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ final FileChooserDescriptor dirChooser = FileChooserDescriptorFactory.createSingleFolderDescriptor();
+ dirChooser.setShowFileSystemRoots(true);
+ dirChooser.setHideIgnored(true);
+ dirChooser.setTitle(UIBundle.message("file.chooser.default.title"));
+ FileChooserDialog chooser = FileChooserFactory.getInstance().createFileChooser(dirChooser, myContentPane);
+ VirtualFile[] files = chooser.choose(null, null);
+ for (VirtualFile file : files) {
+ // adding to the end
+ final String path = file.getPath();
+ if (processor.addPath(myWorkingCollection, path)){
+ myListModel.addElement(path);
+ }
+ }
+ }
+ });
+
+ myRemoveButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ int selected = myList.getSelectedIndex();
+ if (selected != -1) {
+ // removing index
+ final String path = (String) myListModel.get(selected);
+ if (processor.removePath(myWorkingCollection, path)){
+ myListModel.remove(selected);
+ }
+ }
+ }
+ });
+ }
+
+ public JPanel getContentPane() {
+ return myContentPane;
+ }
+
+ public List getValues(){
+ return myWorkingCollection;
+ }
+
+ public void reset() {
+ myListModel.clear();
+ myWorkingCollection = new ArrayList(myInitialCollection);
+ for (String path : myWorkingCollection) {
+ myListModel.addElement(path);
+ }
+ }
+
+ public boolean isModified() {
+ return !myWorkingCollection.equals(myInitialCollection);
+ }
+
+ public void apply() {
+ myInitialCollection.clear();
+ myInitialCollection.addAll(myWorkingCollection);
+ }
+
+ public interface PathProcessor {
+ boolean addPath(List paths, String path);
+ boolean removePath(List paths, String path);
+ }
+}
diff --git a/platform/util/util.iml b/platform/util/util.iml
index 315d1bbcb801..619f920cf77c 100644
--- a/platform/util/util.iml
+++ b/platform/util/util.iml
@@ -16,6 +16,7 @@
+