I have created a JList using GrazedLists, specifically an EventList which I then pass into a SeparatorList with a custom Comparator that sorts my EventList elements. I am using a DefaultEventListModel as the JList model, passing in my SeparatorList. And I am using a custom CellRenderer to decorate the SeparatorList.Separator cells. All is displaying nicely, I see a nicely formatted list grouped as I like, similar to optgroups in HTML SELECT elements.
Now I would like to prevent selection of the Separator cells.
I see examples of how to override the DefaultComboBoxModel. However I have no idea how to override the DefaultListSelectionModel or the DefaultEventListModel.
Here is some example code of what I have so far:
public class MyFrame extends javax.swing.JFrame {
private final EventList<BibleVersion> bibleVersions;
private final SeparatorList<BibleVersion> versionsByLang;
public MyFrame(){
bibleVersions = new BasicEventList<>();
bibleVersions.add(new BibleVersion("CEI2008", "Testo della Conferenza Episcopale Italiana", "2008", "Italian"));
bibleVersions.add(new BibleVersion("LUZZI", "Diodati Nuova Riveduta - Luzzi", "1927", "Italian"));
bibleVersions.add(new BibleVersion("NVBSE", "Nova Vulgata - Bibliorum Sacrorum Editio", "1979", "Latin"));
bibleVersions.add(new BibleVersion("NABRE", "New American Bible - Revised Edition", "2011", "English"));
bibleVersions.add(new BibleVersion("KJV", "King James Version", "1611", "English"));
versionsByLang = new SeparatorList<>(bibleVersions, new VersionComparator(),1, 1000);
jList = new javax.swing.JList();
jList.setModel(new DefaultEventListModel<>(versionsByLang));
jList.setCellRenderer(new VersionCellRenderer());
}
public static class BibleVersion {
private String abbrev;
private String fullname;
private String year;
private String lang;
public BibleVersion(String abbrev, String fullname, String year, String lang) {
this.abbrev = abbrev;
this.fullname = fullname;
this.year = year;
this.lang = lang;
}
public String getAbbrev() {
return abbrev;
}
public void setAbbrev(String abbrev) {
this.abbrev = abbrev;
}
public String getFullname() {
return fullname;
}
public void setFullname(String fullname) {
this.fullname = fullname;
}
public String getYear() {
return year;
}
public void setYear(String year) {
this.year = year;
}
public String getLang() {
return lang;
}
public void setLang(String lang) {
this.lang = lang;
}
@Override
public String toString() {
return this.getAbbrev() + " — " + this.getFullname() + " (" + this.getYear() + ")"; //To change body of generated methods, choose Tools | Templates.
}
}
private static class VersionComparator implements Comparator<BibleVersion> {
@Override
public int compare(BibleVersion o1, BibleVersion o2) {
return o1.getLang().compareTo(o2.getLang());
}
}
private static class VersionCellRenderer extends DefaultListCellRenderer{
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value instanceof SeparatorList.Separator) {
SeparatorList.Separator separator = (SeparatorList.Separator) value;
BibleVersion bibleversion = (BibleVersion)separator.getGroup().get(0);
String lbl = "-- " + bibleversion.getLang() + " --";
label.setText(lbl);
label.setFont(label.getFont().deriveFont(Font.BOLD));
label.setBackground(Color.LIGHT_GRAY);
label.setBorder(BorderFactory.createEmptyBorder(0,5,0,0));
} else {
label.setFont(label.getFont().deriveFont(Font.PLAIN));
label.setBorder(BorderFactory.createEmptyBorder(0,15,0,0));
}
return label;
}
}
}
Now how do I ovveride DefaultEventListModel (or ListSelectionModel)? Which of those do I need to override, or perhaps DefaultListSelectionModel? ListSelectionModel seems to have many methods that would need to be overridden, for handling MULTIPLE_INTERVAL selection (which is my case). I'm not quite sure where to start...
Through some trial and error, based on the code suggestions that I found at https://stackoverflow.com/questions/8344393/disable-items-in-jlist and building up on them, I was able to put together something that is now working quite well. I had to change around the logic in the linked example. Basically I walk between the selected indexes and check one by one if they are an "enabled" index, and if so I "addSelectionInterval" just for that index. I do this both for the setSelectionInterval method and for the addSelectionInterval method. So basically you're never adding a selection as a block, always one at a time by looping through the selection block and checking one by one if they are enabled for selection or not.
Written like this it's working perfectly, the disabled cells are not being selected with CTRL-click at all and SHIFT-clicking works quite nicely also. A single click clears the list and selects only the clicked element if enabled for selection.