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    }