diff --git a/platform/platform-impl/src/com/intellij/util/ui/ComboBoxWithHistory.java b/platform/platform-impl/src/com/intellij/util/ui/ComboBoxWithHistory.java new file mode 100644 index 000000000000..b64fc9698624 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/util/ui/ComboBoxWithHistory.java @@ -0,0 +1,162 @@ +package com.intellij.util.ui; + +import com.intellij.ide.util.PropertiesComponent; +import com.intellij.openapi.project.Project; +import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.HashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + +import javax.swing.*; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.StringReader; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +/** + * @author Konstantin Bulenkov + */ +@SuppressWarnings({"UnusedDeclaration"}) +public class ComboBoxWithHistory extends JComboBox { + private final String myHistoryId; + private Project myProject; + private final HashMap myWeights = new HashMap(); + private boolean myAutoSave = true; + + public ComboBoxWithHistory(@Nullable Project project, String historyId, Object[] items) { + super(); + myHistoryId = historyId; + myProject = project; + setModelFrom(items); + } + + public ComboBoxWithHistory(@NotNull String historyId, Object[] items) { + this(null, historyId, items); + } + + public ComboBoxWithHistory(String historyId) { + this(null, historyId, ArrayUtil.EMPTY_OBJECT_ARRAY); + } + + public void setModelFrom(Object... items) { + setModel(new MyModel(items)); + } + + public boolean isAutoSave() { + return myAutoSave; + } + + public void setAutoSave(boolean autoSave) { + myAutoSave = autoSave; + } + + public void save() { + final StringBuilder buf = new StringBuilder(""); + for (Object key : myWeights.keySet()) { + if (key != null) { + final Long value = myWeights.get(key); + if (value != null) { + buf.append("") + .append("").append(key).append("") + .append("").append(value).append("") + .append(""); + } + } + } + + final String xml = buf.append("").toString(); + + if (myProject == null) { + PropertiesComponent.getInstance().setValue(myHistoryId, xml); + } else { + PropertiesComponent.getInstance(myProject).setValue(myHistoryId, xml); + } + } + + public void load() { + final String xml = myProject == null ? PropertiesComponent.getInstance().getValue(myHistoryId) + : PropertiesComponent.getInstance(myProject).getValue(myHistoryId); + myWeights.clear(); + + if (xml == null) return; + + try { + final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + final DocumentBuilder db = dbf.newDocumentBuilder(); + final InputSource is = new InputSource(); + is.setCharacterStream(new StringReader(xml)); + + Document doc = db.parse(is); + NodeList nodes = doc.getElementsByTagName("map"); + if (nodes.getLength() == 1) { + final NodeList map = nodes.item(0).getChildNodes(); + for (int i = 0; i < map.getLength(); i++) { + final Node item = map.item(i); + final NodeList list = item.getChildNodes(); + final Element key = (Element)list.item(0); + final Element value = (Element)list.item(1); + myWeights.put(key.getTextContent(), Long.valueOf(value.getTextContent())); + } + } + } + catch (Exception e) {// + } + } + + public void setProject(Project project) { + myProject = project; + load(); + } + + private static Object[] sort(final Object[] items, HashMap weights) { + Arrays.sort(items, new LastUsedComparator(weights, Arrays.asList(items))); + return items; + } + + + private class MyModel extends DefaultComboBoxModel { + private MyModel(Object[] items) { + super(sort(items, myWeights)); + } + + @Override + public void setSelectedItem(Object o) { + super.setSelectedItem(o); + if (o != null && isAutoSave()) { + myWeights.put(o.toString(), System.currentTimeMillis()); + save(); + } + } + } + + private static class LastUsedComparator implements Comparator { + private final HashMap myWeights; + private final List myInitialPositions; + + private LastUsedComparator(HashMap weights, List initialPositions) { + myWeights = weights; + myInitialPositions = initialPositions; + } + + @Override + public int compare(Object o1, Object o2) { + final Long w1 = myWeights.get(o1); + final Long w2 = myWeights.get(o2); + if (w1 != null || w2 != null) { + return w1 != null && w2 != null ? sign(w2 - w1) : w1 != null ? -1 : 1; + } + return myInitialPositions.indexOf(o1) - myInitialPositions.indexOf(o2); + } + + private static int sign(Long l) { + return l == 0 ? 0 : l < 0 ? -1 : 1; + } + } +}