001    /**
002     * DisplayCasesMethod.java
003     * jCOLIBRI2 framework. 
004     * @author Juan A. Recio-García.
005     * GAIA - Group for Artificial Intelligence Applications
006     * http://gaia.fdi.ucm.es
007     * 24/10/2007
008     */
009    package jcolibri.extensions.recommendation.casesDisplay;
010    
011    import java.awt.BorderLayout;
012    import java.awt.Dimension;
013    import java.awt.event.ActionEvent;
014    import java.awt.event.ActionListener;
015    import java.util.ArrayList;
016    import java.util.Collection;
017    
018    import javax.swing.Box;
019    import javax.swing.BoxLayout;
020    import javax.swing.JButton;
021    import javax.swing.JDialog;
022    import javax.swing.JLabel;
023    import javax.swing.JPanel;
024    import javax.swing.SpringLayout;
025    
026    import jcolibri.cbrcore.Attribute;
027    import jcolibri.cbrcore.CBRCase;
028    import jcolibri.cbrcore.CaseComponent;
029    import jcolibri.exception.AttributeAccessException;
030    import jcolibri.method.gui.utils.LayoutUtils;
031    import jcolibri.method.gui.utils.WindowUtils;
032    import jcolibri.util.AttributeUtils;
033    
034    /**
035     * Displays the cases in a panel with a "previous" and "next" buttons to 
036     * move through the cases.<br> 
037     * This method is useful when showing composed cases.<br> 
038     * It allways shows an "Add to Basket" and a "Quit" buttons. Optionally it
039     * shows an "Edit Query" button for conversational recommenders (not useful 
040     * in one-shot recommenders).<br>
041     * The methods of this class return an UserChoice object.
042     * 
043     * @author Juan A. Recio-Garcia
044     * @author Developed at University College Cork (Ireland) in collaboration with Derek Bridge.
045     * @version 1.0
046     * @see jcolibri.extensions.recommendation.casesDisplay.UserChoice
047     */
048    public class DisplayCasesMethod
049    {
050        /** Shown cases */
051        private static CBRCase[] _cases;
052        /** ith case currently shown */
053        private static int i = 0;
054        
055        /** Main panel */
056        private static JPanel casesPanel;
057        /** Dialog object */
058        private static JDialog dialog;
059        /** Option to return */
060        private static int returnCode = UserChoice.QUIT;
061        /** Selected case to return */
062        private static CBRCase selectedCase = null;
063        
064        /**
065         * Shows the dialog without the "Edit Query" option
066         * @param cases to display
067         * @return UserChoice object
068         */
069        public static UserChoice displayCases(Collection<CBRCase> cases)
070        {
071            return displayCases(cases, false);
072        }
073        
074        /**
075         * Shows the dialog without the "Edit Query" option
076         * @param cases to display
077         * @return UserChoice object
078         */
079        public static UserChoice displayCasesWithEditOption(Collection<CBRCase> cases)
080        {
081            return displayCases(cases, true);
082        }
083        
084        /**
085         * Shows the dialog and allows to choose if show the "Edit Query" option.
086         * @param cases to display.
087         * @param editQueryEnabled decides if show the "Edit Query" option.
088         * @return UserChoice object.
089         */
090        public static UserChoice displayCases(Collection<CBRCase> cases, boolean editQueryEnabled)
091        {
092            _cases = new CBRCase[cases.size()];
093            cases.toArray(_cases);
094            dialog = new JDialog();
095            dialog.setModal(true);
096            
097            JPanel main = new JPanel();
098            main.setLayout(new BorderLayout());
099            
100            casesPanel = new JPanel();
101            casesPanel.setLayout(new BoxLayout(casesPanel, BoxLayout.Y_AXIS));
102            displayCase();
103            main.add(casesPanel, BorderLayout.CENTER);
104            
105            JPanel actionsPanel = new JPanel();
106            actionsPanel.setLayout(new BoxLayout(actionsPanel,BoxLayout.X_AXIS));
107            
108            JButton next = new JButton("Next >>");
109            next.addActionListener(new ActionListener(){
110                public void actionPerformed(ActionEvent arg0)
111                {
112                    i = (i+1)%_cases.length;
113                    displayCase();
114                } 
115            });
116            JButton prev = new JButton("<< Previous");
117            prev.addActionListener(new ActionListener(){
118                public void actionPerformed(ActionEvent arg0)
119                {
120                    i = (i-1)%_cases.length;
121                    displayCase();
122                } 
123            }); 
124            JButton ok = new JButton("Add to Basket");
125            ok.addActionListener(new ActionListener(){
126                public void actionPerformed(ActionEvent arg0)
127                {
128                    returnCode = UserChoice.BUY;
129                    selectedCase = _cases[i];
130                    dialog.setVisible(false);
131                } 
132            });
133            JButton quit = new JButton("Quit");
134            quit.addActionListener(new ActionListener(){
135                public void actionPerformed(ActionEvent arg0)
136                {
137                    returnCode = UserChoice.QUIT;
138                    dialog.setVisible(false);
139                } 
140            });
141            JButton refine = new JButton("Edit Query");
142            refine.addActionListener(new ActionListener(){
143                public void actionPerformed(ActionEvent arg0)
144                {
145                    returnCode = UserChoice.REFINE_QUERY;
146                    dialog.setVisible(false);
147                } 
148            });
149            refine.setEnabled(editQueryEnabled);
150            
151            actionsPanel.add(ok);
152            actionsPanel.add(quit);
153            if(editQueryEnabled)
154                actionsPanel.add(refine);
155            actionsPanel.add(Box.createHorizontalGlue());
156            actionsPanel.add(prev);
157            actionsPanel.add(next);
158            
159            main.add(actionsPanel, BorderLayout.SOUTH);
160            
161            dialog.getContentPane().add(main);
162            dialog.pack();
163            dialog.setSize(new Dimension((int)dialog.getSize().getWidth()+50, (int)dialog.getSize().getHeight()));
164            WindowUtils.centerWindow(dialog);
165            dialog.setTitle(cases.size()+" Retrieved cases");
166            dialog.setVisible(true);
167            
168            return new UserChoice(returnCode, selectedCase);
169        }
170    
171        /**
172         * Displays a case
173         */
174        private static void displayCase()
175        {
176            casesPanel.removeAll();
177            CBRCase c = _cases[i];
178            
179            displayCaseComponent(c.getDescription(),"Description",casesPanel);
180            displayCaseComponent(c.getSolution(),"Solution",casesPanel);
181            displayCaseComponent(c.getJustificationOfSolution(),"Justification of Solution",casesPanel);
182            displayCaseComponent(c.getResult(),"Result",casesPanel);
183            
184            casesPanel.validate();
185            casesPanel.repaint();
186    
187            dialog.setTitle("Case "+(i+1)+"/"+_cases.length);
188        }
189        
190        /**
191         * Displays a case component
192         * @param cc is the case component to display
193         * @param title of the panel
194         * @param parentPanel is the parent panel. 
195         */
196        private static void displayCaseComponent(CaseComponent cc, String title, JPanel parentPanel)
197        {
198            if(cc==null)
199                return;
200            
201            JPanel panel = new JPanel();
202            panel.setBorder(javax.swing.BorderFactory.createTitledBorder(title));
203            
204            panel.setLayout(new BoxLayout(panel,BoxLayout.Y_AXIS));
205            JPanel simplePanel = new JPanel();
206            simplePanel.setLayout(new SpringLayout());
207            
208            JPanel compoundPanel = new JPanel();
209            compoundPanel.setLayout(new BoxLayout(compoundPanel,BoxLayout.Y_AXIS));
210    
211            try
212            {
213                Attribute[] ats = jcolibri.util.AttributeUtils.getAttributes(cc.getClass());
214                
215                ArrayList<Attribute> compounds = new ArrayList<Attribute>();
216                int sAtts = 0;
217                for(Attribute a: ats)
218                {
219                    if(a.getType().equals(CaseComponent.class))
220                    {
221                        compounds.add(a);
222                    }
223                    else
224                    {
225                        simplePanel.add(new JLabel(a.getName()));
226                        simplePanel.add(new JLabel(a.getValue(cc).toString()));
227                        sAtts++;
228                    }
229                }
230                LayoutUtils.makeCompactGrid(simplePanel, sAtts,2,5,5,15,5);
231                
232                
233                //Now process compounds
234                for(Attribute comp: compounds)
235                    displayCaseComponent((CaseComponent)comp.getValue(cc), comp.getName(),compoundPanel);
236                
237                
238                panel.add(simplePanel);
239                panel.add(compoundPanel);
240                
241                casesPanel.add(panel);
242            } catch (AttributeAccessException e)
243            {
244                org.apache.commons.logging.LogFactory.getLog(AttributeUtils.class).error(e);
245            }
246        }
247    
248    }