001 /*
002 * SimuCS - Simulator to use with Classifier Systems
003 * MSc project - Oxford University
004 * by Benoit Isaac - Summer 2005
005 */
006
007 package simuLCS.graphics;
008 import java.awt.BorderLayout;
009 import java.awt.Component;
010 import java.awt.FlowLayout;
011 import java.awt.Graphics;
012 import java.awt.event.ActionEvent;
013 import java.util.Iterator;
014 import java.util.Set;
015
016 import javax.swing.AbstractAction;
017 import javax.swing.ButtonGroup;
018 import javax.swing.DefaultListModel;
019 import javax.swing.JCheckBox;
020 import javax.swing.JLabel;
021 import javax.swing.JList;
022 import javax.swing.JRadioButton;
023 import javax.swing.JScrollPane;
024 import javax.swing.ListCellRenderer;
025 import javax.swing.ListSelectionModel;
026 import javax.swing.event.ListDataEvent;
027 import javax.swing.event.ListDataListener;
028 import javax.swing.event.ListSelectionEvent;
029 import javax.swing.event.ListSelectionListener;
030
031 import simuLCS.Agent;
032 import simuLCS.AgentClassifierLearning;
033 import simuLCS.Classifier;
034 import simuLCS.Entity;
035
036 /**
037 * A component used to display a list of classifiers
038 * @author Benoit
039 *
040 */
041 public class G_ListClassifiers
042 extends G_Panel
043 implements ListSelectionListener {
044
045 private JList list;
046 private DefaultListModel listModel;
047
048 /**
049 * @see AgentClassifierLearning#getBehaviour(int)
050 */
051 private int behaviourToShow;
052
053 private boolean isEnabled;
054 private boolean withFilters;
055 private Set linkedWith;
056
057 private boolean hasBeenRepainted = false ;
058
059 private JScrollPane scrollpanClassifier;
060
061 private Classifier previousSelectedClassifier = null;
062 private G_ListClassifiers listToUpdate;
063
064 private G_Panel panelToUpdate;
065
066 private int condMatch = Classifier.COND_MATCH;
067 private int actMatch = Classifier.ACT_ALL;
068
069 public G_ListClassifiers(
070 Set toLinkWith,
071 int maxVisibleRows,
072 int whichBehaviour,
073 boolean toEnable,
074 G_Panel toUpdate,
075 boolean filters) {
076 super();
077
078 behaviourToShow = whichBehaviour;
079 isEnabled = toEnable;
080 linkedWith = toLinkWith;
081 panelToUpdate = toUpdate;
082 withFilters = filters;
083 setLayout(new BorderLayout());
084 //Create and populate the list model.
085 listModel = new DefaultListModel();
086 listModel.addListDataListener(new MyListDataListener());
087
088 //Create the list and put it in a scroll pane.
089 list = new JList(listModel);
090 if (behaviourToShow
091 == AgentClassifierLearning.EXPECTED_BEHAVIOUR_TO_SHOW) {
092 list.setSelectionMode(
093 ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
094 } else {
095 list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
096 }
097
098 // list.setSelectedIndex(0);
099 list.addListSelectionListener(this);
100 if (behaviourToShow
101 == AgentClassifierLearning.EXPECTED_BEHAVIOUR_TO_SHOW)
102 list.setCellRenderer(new MyCellRenderer());
103 list.setVisibleRowCount(maxVisibleRows);
104 list.setEnabled(isEnabled);
105 updateValues();
106 JScrollPane listScrollPane = new JScrollPane(list);
107 add(listScrollPane, BorderLayout.CENTER);
108
109 if (withFilters)
110 add(createFiltersPanel(), BorderLayout.SOUTH);
111 }
112
113 /**
114 * Class used to reimplement the ListCellRenderer in order to highlight
115 * the classifiers matching the special conditions
116 * @author Benoit
117 *
118 */
119 class MyCellRenderer extends JLabel implements ListCellRenderer {
120
121 // This is the only method defined by ListCellRenderer.
122 // We just reconfigure the JLabel each time we're called.
123
124 public Component getListCellRendererComponent(JList list, Object value,
125 // value to display
126 int index, // cell index
127 boolean isSelected, // is the cell selected
128 boolean cellHasFocus) // the list and the cell have the focus
129 {
130 Classifier selected = G_Panel.getCurrentClassifier();
131 StringBuffer s =
132 new StringBuffer(value.toString() + " rk:" + (index + 1));
133 if (selected != null
134 && behaviourToShow
135 == AgentClassifierLearning.EXPECTED_BEHAVIOUR_TO_SHOW
136 && ((Classifier) value).match(
137 selected,
138 Classifier.COND_ALL,
139 Classifier.ACT_EXACT)) {
140 s.append(" -EXACT-");
141 }
142
143 setText(s.toString());
144 if (isSelected) {
145 setBackground(list.getSelectionBackground());
146 setForeground(list.getSelectionForeground());
147 } else {
148 setBackground(list.getBackground());
149 setForeground(list.getForeground());
150 }
151 setEnabled(list.isEnabled());
152 setFont(list.getFont());
153 setOpaque(true);
154 return this;
155 }
156 }
157
158 /**
159 * Creates the filters buttons for the highlighting
160 * @return
161 */
162 public G_Panel createFiltersPanel() {
163 G_Panel r = new G_Panel();
164
165 JLabel j1 = new JLabel("Condition:");
166 JLabel j2 = new JLabel("- Action:");
167 ButtonGroup bg = new ButtonGroup();
168
169 class ActButton extends AbstractAction {
170 public void actionPerformed(ActionEvent evt) {
171 JRadioButton b = (JRadioButton) evt.getSource();
172 if (b.getActionCommand().equals("Exact")) {
173 condMatch = Classifier.COND_EXACT;
174 } else {
175 condMatch = Classifier.COND_MATCH;
176 }
177 repaint();
178 }
179
180 }
181
182 JRadioButton cMatch = new JRadioButton("Match");
183 cMatch.setActionCommand("Match");
184 cMatch.addActionListener(new ActButton());
185 JRadioButton cExact = new JRadioButton("Exact");
186 cExact.setActionCommand("Exact");
187 cExact.addActionListener(new ActButton());
188
189 bg.add(cMatch);
190 bg.add(cExact);
191
192 class ActCheckBox extends AbstractAction {
193 public void actionPerformed(ActionEvent evt) {
194 JCheckBox b = (JCheckBox) evt.getSource();
195 //Determine status
196 boolean isSel = b.isSelected();
197 if (isSel) {
198 actMatch = Classifier.ACT_EXACT;
199 } else {
200 // The checkbox is now deselected
201 actMatch = Classifier.ACT_ALL;
202 }
203 repaint();
204 }
205 }
206 JCheckBox aExact = new JCheckBox("Exact");
207 aExact.addActionListener(new ActCheckBox());
208
209 // by default
210 cMatch.setSelected(true);
211 condMatch = Classifier.COND_MATCH;
212 actMatch = Classifier.ACT_ALL;
213
214 r.setLayout(new FlowLayout());
215 r.add(j1);
216 r.add(cMatch);
217 r.add(cExact);
218 r.add(j2);
219 r.add(aExact);
220
221 return r;
222
223 }
224
225 public class MyListDataListener implements ListDataListener {
226 public void contentsChanged(ListDataEvent e) {
227 updateValues();
228 // panClassifier.updateValues();
229 // log.append("contentsChanged: " + e.getIndex0() +
230 // ", " + e.getIndex1() + newline);
231 // log.setCaretPosition(log.getDocument().getLength());
232 }
233 public void intervalAdded(ListDataEvent e) {
234 // log.append("intervalAdded: " + e.getIndex0() +
235 // ", " + e.getIndex1() + newline);
236 // log.setCaretPosition(log.getDocument().getLength());
237 }
238 public void intervalRemoved(ListDataEvent e) {
239 // log.append("intervalRemoved: " + e.getIndex0() +
240 // ", " + e.getIndex1() + newline);
241 // log.setCaretPosition(log.getDocument().getLength());
242 }
243 }
244
245 //Listener method for list selection changes.
246 public void valueChanged(ListSelectionEvent e) {
247 if (e.getValueIsAdjusting() == false) {
248
249 if (list.getSelectedIndex() == -1) {
250 //No selection: disable change, delete, up, and down buttons.
251
252 } else if (list.getSelectedIndices().length > 1) {
253 //Multiple selection: disable up and down buttons.
254
255 } else {
256 if (behaviourToShow == AgentClassifierLearning.REAL_BEHAVIOUR)
257 G_Panel.setCurrentClassifier(
258 (Classifier) list.getSelectedValue());
259 if (panelToUpdate != null) {
260 // System.out.println("We should repaint the panel:"+panelToUpdate);
261 panelToUpdate.updateValues();
262 }
263 // if(!hasBeenRepainted)
264 // {
265 // hasBeenRepainted = true;
266 // repaintCustom();
267 // }
268 // else
269 // {
270 // hasBeenRepainted = false;
271 // }
272 //Single selection: permit all operations.
273
274 }
275 }
276 }
277
278 /**
279 * Updating the list of classifiers shown inside the component
280 */
281 public void updateValues() {
282 Classifier current = (Classifier) list.getSelectedValue();
283 listModel.removeAllElements();
284 boolean isShared;
285 Classifier currentClassifier;
286 Entity[] en = new Entity[0];
287 en = (Entity[]) linkedWith.toArray(en);
288
289 // System.out.println("In paintComponent for G_listPanel, "+ag.length+" selected.");
290 // if(ag.length != 0)
291 // System.out.println("[ListClassifiers] "+ag[0].getName()+" "+
292 // ag[0].getBehaviour(behaviourToShow));
293
294 if (en.length != 0 && en[0] instanceof Agent) {
295 Agent a = (Agent) en[0];
296 if (a.getBehaviour(behaviourToShow) != null) {
297 Iterator iter = a.getBehaviour(behaviourToShow).getIterator();
298 /*
299 * for each classifier of the first agent, we check if this classifier
300 * is shared by all the others agents
301 */
302
303 while (iter.hasNext()) {
304 currentClassifier = (Classifier) iter.next();
305 isShared = true;
306 // System.out.println("Test: is it shared? "+currentClassifier);
307 if (en.length > 1) // more than one entity selected
308 {
309 /* we need to check that this classifier is shared by all
310 * the selected entities
311 */
312 for (int i = 1; i < selectedEntities.size(); i++) {
313 if (en[i] instanceof Agent) {
314 Agent cur = (Agent) en[i];
315 if (cur.getBehaviour(behaviourToShow) != null
316 && (!cur.getBehaviour(behaviourToShow)
317 .contains(currentClassifier))) {
318 // this classifier should not be shown
319 isShared = false;
320 }
321 } else {
322 isShared = false;
323 }
324 }
325 }
326
327 if (isShared) {
328 listModel.addElement(currentClassifier);
329 // System.out.println("Shared:"+currentClassifier);
330 }
331 }
332 }
333 }
334 list.validate();
335 if (listModel.getSize() > 0) {
336 if (isEnabled) { // select the current one
337 if (current != null && listModel.contains(current)) {
338 list.setSelectedValue(current, true);
339 G_Panel.setCurrentClassifier(current);
340 } else {
341 list.setSelectedIndex(0);
342 G_Panel.setCurrentClassifier(
343 (Classifier) listModel.getElementAt(0));
344 }
345 } else if (
346 behaviourToShow
347 == AgentClassifierLearning.EXPECTED_BEHAVIOUR_TO_SHOW) {
348 // we select all the matching classifiers
349 Classifier currentCl;
350 int[] listToSelect = new int[listModel.getSize()];
351 Classifier selected = G_Panel.getCurrentClassifier();
352 // System.out.println("Current Condition:" + cond);
353 int j = 0;
354 for (int i = 0; i < listModel.getSize(); i++) {
355 currentCl = (Classifier) listModel.getElementAt(i);
356 if (currentCl.match(selected, condMatch, actMatch)) {
357 listToSelect[j] = i;
358 j++;
359 }
360 }
361 int[] listToSelectFinal = new int[j];
362 for (int l = 0; l < j; l++)
363 listToSelectFinal[l] = listToSelect[l];
364 list.setSelectedIndices(listToSelectFinal);
365 }
366
367 }
368
369 }
370
371 public void paintComponent(Graphics g) {
372 // System.out.println("In paintComponent for G_listPanel, "+selectedEntities+" selected.");
373 updateValues();
374 // panClassifier.updateValues();
375 }
376
377 /**
378 * @return
379 */
380 public JList getList() {
381 return list;
382 }
383
384 /**
385 * @return
386 */
387 public DefaultListModel getListModel() {
388 return listModel;
389 }
390
391 }