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 }