blob: b64fc969862470e58a9c296ecd5614cea38bb49f [file] [log] [blame]
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<Object, Long> myWeights = new HashMap<Object, Long>();
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("<map>");
for (Object key : myWeights.keySet()) {
if (key != null) {
final Long value = myWeights.get(key);
if (value != null) {
buf.append("<element>")
.append("<key>").append(key).append("</key>")
.append("<value>").append(value).append("</value>")
.append("</element>");
}
}
}
final String xml = buf.append("</map>").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<Object, Long> 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<Object> {
private final HashMap<Object, Long> myWeights;
private final List<Object> myInitialPositions;
private LastUsedComparator(HashMap<Object, Long> weights, List<Object> 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;
}
}
}