001 // GraphLab Project: http://graphlab.sharif.edu 002 // Copyright (C) 2008 Mathematical Science Department of Sharif University of Technology 003 // Distributed under the terms of the GNU General Public License (GPL): http://www.gnu.org/licenses/ 004 005 package graphlab.ui; 006 007 import graphlab.platform.core.AbstractAction; 008 import graphlab.platform.core.BlackBoard; 009 import graphlab.platform.extension.Extension; 010 import graphlab.platform.lang.CommandAttitude; 011 import graphlab.platform.parameter.Parameter; 012 import graphlab.platform.parameter.Parametrizable; 013 import graphlab.ui.components.ExtensionConfigFrame; 014 import graphlab.ui.components.GFrame; 015 import graphlab.ui.components.gmenu.GMenuBar; 016 import graphlab.ui.components.gmenu.GMenuItem; 017 import graphlab.ui.xml.UIHandlerImpl; 018 019 import javax.swing.*; 020 import javax.swing.border.EmptyBorder; 021 import java.awt.*; 022 import java.awt.event.ActionEvent; 023 import java.awt.event.ActionListener; 024 import java.awt.event.MouseAdapter; 025 import java.awt.event.MouseEvent; 026 import java.lang.reflect.Field; 027 028 /** 029 * the base class for creating extension handlers 030 * the implementing class will have a menu assigned to it automatically the name of the menu will be 031 * from the constructors parametr(sp) and the will also listen to UI.getUIEvent(sp.getName()) 032 * 033 * @author azin azadi 034 035 */ 036 public abstract class AbstractExtensionAction<t extends Extension> extends AbstractAction implements ActionListener { 037 //todo: Write how to create new extension types document. 038 protected JMenu parentMenu; 039 public GMenuItem menuItem; 040 ExtensionConfigFrame ecf; 041 /** 042 * a button which will be added to the right of menu item 043 */ 044 protected JButton extraButton; 045 046 public t getTarget() { 047 return target; 048 } 049 050 public t target; 051 052 public AbstractExtensionAction(BlackBoard bb, t sp) { 053 super(bb); 054 target = sp; 055 String name = getMenuNamePrefix() + sp.getName(); 056 String actionId = name + sp.getDescription(); 057 listen4Event(UIUtils.getUIEventKey(actionId)); 058 if (!name.equals("")) { 059 menuItem = createMenuItem(name, actionId, bb); 060 parentMenu = getParentMenu(); 061 if (parentMenu != null) 062 GMenuBar.insert(parentMenu, menuItem, getMenuPlace()); 063 } 064 createExtensionCommandsForCommandLine(); 065 } 066 067 /** 068 * It is a XML-Based UI concept 069 * 070 * @return the place which the extension menu will be inserted in its parents menu, the place is 071 * only a comparative value, it means that Menu Items with bigger place will be inserted after smaller place Menue Items 072 */ 073 protected int getMenuPlace() { 074 return 40; 075 } 076 077 /** 078 * if you want to create custom menues for your extension (i.e. want to add some extra components to it) you should 079 * override this method. 080 * 081 * @param name 082 * @param actionId 083 * @param bb 084 * @return 085 * @see graphlab.plugins.algorithmanimator.extension.AlgorithmExtensionAction 086 */ 087 protected final GMenuItem createMenuItem(String name, String actionId, BlackBoard bb) { 088 int index = Math.max(name.indexOf(UIHandlerImpl.menueIndexChar), 0); 089 String labelString = name.replace(UIHandlerImpl.menueIndexChar + "", ""); 090 if (isInsertExtraButtonToMenuItem()) { 091 GMenuItem menuItem = new GMenuItem(labelString, actionId, bb, null, index) { 092 public Dimension getPreferredSize() { 093 Dimension preferredSize = super.getPreferredSize(); 094 Dimension bps = extraButton.getPreferredSize(); 095 preferredSize.width += bps.getWidth() + 4; 096 preferredSize.height = (int) Math.max(preferredSize.height, bps.getHeight()) + 1; 097 return preferredSize; 098 } 099 100 }; 101 String imageURL = "/graphlab/plugins/main/resources/edit16_.gif"; 102 extraButton = new JButton(new ImageIcon(getClass().getResource(imageURL))); 103 extraButton.setBorder(new EmptyBorder(0, 0, 0, 0)); 104 extraButton.addActionListener(this); 105 extraButton.addMouseListener(new MouseAdapter() { 106 public void mouseClicked(MouseEvent e) { 107 actionPerformed(null); 108 } 109 }); 110 menuItem.setLayout(new BorderLayout()); 111 menuItem.add(extraButton, BorderLayout.EAST); 112 return menuItem; 113 } else 114 return new GMenuItem(name, actionId, bb); 115 } 116 117 /** 118 * determines wheter to insert an extra button at the right side of mene item, 119 * normally this is true whenever the target extension implements Parametrizable (have some parameters) 120 * on this mode on pressing the button a dialog for setting the parameters will be shown, and then 121 * it will be executed, if the user clicks the menu item directly the extension will be 122 * performed without asking of parameters. 123 * <p/> 124 * if you want to override this method for your own ExtensionAction 125 * NOTE that on pressing the button the actionPerformed will be called, so you can 126 * do what you want to do by overriding that method. 127 * 128 * @return true to insert the extra button, false to no insert it. 129 * @see Parametrizable 130 * @see @Parameter 131 * @see graphlab.plugins.algorithmanimator.extension.AlgorithmExtensionAction 132 */ 133 protected boolean isInsertExtraButtonToMenuItem() { 134 return target instanceof Parametrizable; 135 } 136 137 /** 138 * inorder if you created a new type of extension and for that extension you want to do some thing different 139 * when it is called on commandline (i.e. in normal state it uses some GUI functionalities and you want to avoid them) 140 * you can override this method and do what you want, which will 141 * be called whenever your extension called from commandline 142 * for an example see GraphGeneratorExtensionAction 143 * 144 * @see graphlab.plugins.graphgenerator.core.extension.GraphGeneratorExtensionAction 145 */ 146 public Object performExtensionInCommandLine() { 147 performExtension(); 148 return null; 149 } 150 151 protected void createExtensionCommandsForCommandLine() { 152 final AbstractExtensionAction<t> ths = this; 153 final t trgClass = target; 154 final CommandAttitude comati = trgClass.getClass().getAnnotation(CommandAttitude.class); 155 156 String command = ""; 157 CommandAttitude c = comati; 158 String cname; 159 String abrv; 160 String desc; 161 if (c != null) { 162 // Shell.set_variable("_" + target.getClass().getSimpleName(), target); 163 cname = c.name(); 164 abrv = c.abbreviation(); 165 desc = c.description(); 166 if (desc == null || desc.equals("")) 167 desc = target.getDescription(); 168 } else { 169 cname = target.getClass().getSimpleName(); 170 abrv = ""; 171 desc = target.getDescription(); 172 } 173 command += cname + "("; 174 String help = ""; 175 176 for (Field f : target.getClass().getFields()) { 177 if (f.getAnnotation(Parameter.class) != null) { 178 command += f.getType().getName() 179 + " " 180 + f.getName() + ","; 181 help += "_" + target.getClass().getSimpleName() 182 + "." 183 + f.getName() 184 + " = " 185 + f.getName() 186 + ";\n"; 187 } 188 } 189 if (command.endsWith(",")) 190 command = command.substring(0, command.length() - 1); 191 command += ")\n{"; 192 // System.out.println(command); 193 ExtensionShellCommandProvider.addCommand(ths, trgClass, cname, abrv, command, desc, help); 194 195 } 196 197 /** 198 * to put a prefix before the name of your extension menu override this method 199 */ 200 protected String getMenuNamePrefix() { 201 return ""; 202 } 203 204 /** 205 * gets a menu for adding the sub menu, if returns null, no submenu will added! 206 */ 207 protected JMenu getParentMenu() { 208 GFrame f = UIUtils.getGFrame(blackboard); 209 String mname = getParentMenuName(); 210 return f.getMenu().getUniqueMenu(mname, -1); 211 } 212 213 /** 214 * first checks if o instanceof Parametrizable if so, shows an 215 * editor for it's Parameters. 216 * 217 * @param o 218 * @return true if o isn't an instance of Parametrizable or the user cancells the editing 219 */ 220 public boolean testAndSetParameters(Object o) { 221 if (o instanceof Parametrizable) { 222 ParameterShower ps = new ParameterShower(); 223 224 return ps.show((Parametrizable) o); 225 } else 226 return true; 227 } 228 229 /** 230 * removes all UI Components that are created for the extension (menues, ...) 231 */ 232 public void removeCreatedUIComponents() { 233 if (parentMenu != null && menuItem != null) { 234 parentMenu.remove(menuItem); 235 //if parent menu is empty remove it and so on. 236 if (parentMenu.getMenuComponentCount() == 0) { 237 parentMenu.getParent().remove(parentMenu); 238 } 239 } 240 241 } 242 243 /** 244 * returns the menu name that the menuitem of this action is its child 245 */ 246 public abstract String getParentMenuName(); 247 248 public final void performAction(String eventKey, Object value) { 249 performExtension(); 250 } 251 252 /** 253 * occurs whenever extraButton pressed 254 * <p/> 255 * = 256 */ 257 public void actionPerformed(ActionEvent e) { 258 parentMenu.setSelected(false); 259 // final ExtensionExternalData tt = target.getClass().getAnnotation(ExtensionExternalData.class); 260 // ecf = new ExtensionConfigFrame(this.target, tt); 261 // ecf.setAlwaysOnTop(true); 262 // if (tt != null) { 263 // if (tt.helpURL() != null) { 264 // JButton helpBtn = new JButton(new ImageIcon(getClass().getResource("/graphlab/plugins/main/resources/help16.gif"))); 265 // helpBtn.setBorder(new EmptyBorder(0, 0, 0, 0)); 266 // helpBtn.addMouseListener(new MouseAdapter() { 267 // public void mouseClicked(MouseEvent e) { 268 // try { 269 // Browser.browse(new URL(tt.helpURL())); 270 // } catch (MalformedURLException e1) { 271 // e1.printStackTrace(); 272 // } 273 // } 274 // }); 275 // menuItem.add(helpBtn, BorderLayout.EAST); 276 // } 277 // if (tt.sourceCodeURL() != null) { 278 // JButton srcBtn = new JButton(new ImageIcon(getClass().getResource("/graphlab/plugins/main/resources/open16.gif"))); 279 // srcBtn.setBorder(new EmptyBorder(0, 0, 0, 0)); 280 // srcBtn.addMouseListener(new MouseAdapter() { 281 // public void mouseClicked(MouseEvent e) { 282 // try { 283 // Browser.browse(new URL(tt.sourceCodeURL())); 284 // } catch (MalformedURLException e1) { 285 // e1.printStackTrace(); 286 // } 287 // } 288 // }); 289 // menuItem.add(srcBtn, BorderLayout.EAST); 290 // } 291 // } 292 // 293 // 294 // ecf.setVisible(true); 295 if (testAndSetParameters(target)) 296 performExtension(); 297 } 298 299 public abstract void performExtension(); 300 301 }