View Javadoc
1 /* 2 * BeanPeeler.java 3 * Created on 18 January 2001, 18:12 4 */ 5 6 package org.johndavidtaylor.beans.beanpeeler; 7 8 import java.awt.Color; 9 import java.awt.Component; 10 import java.awt.Dimension; 11 import java.awt.Font; 12 import java.awt.GridLayout; 13 import java.awt.Label; 14 import java.beans.BeanInfo; 15 import java.beans.Introspector; 16 import java.beans.PropertyChangeListener; 17 import java.beans.PropertyDescriptor; 18 import java.beans.PropertyEditor; 19 import java.beans.PropertyEditorManager; 20 import java.lang.reflect.Method; 21 import java.util.Enumeration; 22 import java.util.Vector; 23 24 /*** <h3> 25 * Introspects a bean and allows customisation 26 * </h3> 27 * <P> 28 * <STRONG>BeanPeeler</STRONG> is a property sheet allowing you to customize javabeans. 29 * It's similar to the property sheets that you get in IDEs such as Netbeans' Forte that you use to customise components before you 30 * drop them onto a form. It examines a bean for any read/write properties and constructs a property sheet using dropdown boxes for 31 * properties such as booleans which have discrete values and textboxes for strings and numbers. 32 * </P> 33 * <P> 34 * Usage: </P> 35 *<P><code> 36 *MyBean mb = new MyBean(); <br> 37 *BeanPeeler bp = new BeanPeeler(mb); <br> 38 *mb.addPropertyChangeListener(bp); //if appropriate <br> 39 *bp.show(); <br> 40 *<br> 41 *BeanPeeler bp2 = new BeanPeeler(mb, BeanPeeler.ENABLE_OK); //disable Cancel and apply buttons <br> 42 *bp2.showAndWait(); // if you want a modal dialog <br> 43 *</code> 44 * </P> 45 * @author JTAYLOR3 46 * @version 1.2 47 * removed the warning dialog and added a getError method - far less trouble 48 * @version 1.1.1 49 */ 50 public class BeanPeeler extends java.awt.Frame implements PropertyChangeListener { 51 52 /*** Holds value of property bean. */ 53 private Object bean; 54 55 56 57 /*** Creates new form BeanPeeler */ 58 private BeanPeeler() { 59 initComponents (); 60 pack (); 61 } 62 63 /*** Constructs a new BeanPeeler to edit the given bean. 64 * @param bean The bean to be edited. 65 */ 66 public BeanPeeler(Object bean) { 67 this(); 68 this.setBean(bean); 69 setBackground(Color.lightGray); 70 } 71 72 73 /*** Constructs a new BeanPeeler to edit the given bean. 74 * @param bean The bean to be edited. 75 * @param options the allowed options for the buttons (see fields list) = usual bitwise or 76 */ 77 public BeanPeeler(Object bean, int options) { 78 this(bean); 79 OKBtn.setEnabled((options & ENABLE_OK) !=0); 80 CancelBtn.setEnabled((options & ENABLE_CANCEL) !=0); 81 Apply.setEnabled((options & ENABLE_APPLY) !=0); 82 } 83 84 85 86 87 /*** 88 * Show OK button 89 */ 90 public static final int ENABLE_OK = 1; 91 /*** 92 * Show Cancel button 93 */ 94 public static final int ENABLE_CANCEL = 2; 95 /*** 96 * Show Apply button 97 */ 98 public static final int ENABLE_APPLY = 4; 99 100 101 102 103 /*** This method is called from within the constructor to 104 * initialize the form. 105 * WARNING: Do NOT modify this code. The content of this method is 106 * always regenerated by the FormEditor. 107 */ 108 private void initComponents() {//GEN-BEGIN:initComponents 109 titleLabel = new java.awt.Label(); 110 scrollPane1 = new java.awt.ScrollPane(); 111 panel1 = new java.awt.Panel(); 112 panel2 = new java.awt.Panel(); 113 OKBtn = new java.awt.Button(); 114 CancelBtn = new java.awt.Button(); 115 Apply = new java.awt.Button(); 116 117 setBackground(java.awt.Color.lightGray); 118 addWindowListener(new java.awt.event.WindowAdapter() { 119 public void windowClosing(java.awt.event.WindowEvent evt) { 120 exitForm(evt); 121 } 122 }); 123 124 titleLabel.setText("BeanPeeler V1.3 by johndavid_taylor@hotmail.com"); 125 titleLabel.setAlignment(java.awt.Label.CENTER); 126 add(titleLabel, java.awt.BorderLayout.NORTH); 127 128 panel1.setLayout(new java.awt.GridLayout(5, 2)); 129 130 scrollPane1.add(panel1); 131 132 add(scrollPane1, java.awt.BorderLayout.CENTER); 133 134 OKBtn.setLabel("Ok"); 135 //OKBtn.setName("button3"); //@TODO remove this 136 OKBtn.addActionListener(new java.awt.event.ActionListener() { 137 public void actionPerformed(java.awt.event.ActionEvent evt) { 138 OKBtnActionPerformed(evt); 139 } 140 }); 141 142 panel2.add(OKBtn); 143 144 CancelBtn.setLabel("Cancel"); 145 //CancelBtn.setName("button4"); //@TODO remove this 146 CancelBtn.addActionListener(new java.awt.event.ActionListener() { 147 public void actionPerformed(java.awt.event.ActionEvent evt) { 148 CancelBtnActionPerformed(evt); 149 } 150 }); 151 152 panel2.add(CancelBtn); 153 154 Apply.setLabel("Apply"); 155 Apply.addActionListener(new java.awt.event.ActionListener() { 156 public void actionPerformed(java.awt.event.ActionEvent evt) { 157 ApplyActionPerformed(evt); 158 } 159 }); 160 161 panel2.add(Apply); 162 163 add(panel2, java.awt.BorderLayout.SOUTH); 164 165 }//GEN-END:initComponents 166 167 /*** 168 * rescan the bean and update the property editors as appropriate 169 */ 170 private void refresh() { 171 try{ 172 Enumeration e = propDescsWithEditors.elements(); 173 while (e.hasMoreElements()) { 174 BeanProperty bp = (BeanProperty) e.nextElement(); 175 bp.setValueFromBean(bean); 176 } 177 } 178 catch(Exception e){ 179 warn("Couldn't save properties - perhaps some are readonly"); 180 } 181 182 Component[] editors = panel1.getComponents(); 183 for (int i=0; i<editors.length;++i) { 184 if (editors[i] instanceof GEditor) { //@TODO yuk don't use instanceof 185 GEditor g = (GEditor) editors[i]; 186 g.refresh(); 187 } 188 } 189 } 190 191 192 private void ApplyActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ApplyActionPerformed 193 updateBean(); 194 }//GEN-LAST:event_ApplyActionPerformed 195 196 private void updateBean() { 197 try{ 198 Enumeration e = propDescsWithEditors.elements(); 199 while (e.hasMoreElements()) { 200 BeanProperty bp = (BeanProperty) e.nextElement(); 201 bp.setBeanFromValue(bean); 202 } 203 } 204 catch(Exception e){ 205 warn("Couldn't save properties - perhaps some are readonly"); 206 } 207 } 208 private void OKBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_OKBtnActionPerformed 209 updateBean(); 210 setDone(); 211 dispose(); 212 }//GEN-LAST:event_OKBtnActionPerformed 213 214 private void CancelBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_CancelBtnActionPerformed 215 setDone(); 216 dispose(); //forget it 217 }//GEN-LAST:event_CancelBtnActionPerformed 218 219 /*** Exit the Application */ 220 private void exitForm(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_exitForm 221 setDone(); 222 dispose(); 223 }//GEN-LAST:event_exitForm 224 225 private boolean done = false; 226 synchronized private void setDone() { 227 done = true; 228 notifyAll(); 229 } 230 /*** Use instead of {@link show()} if you want a modal dialog 231 */ 232 synchronized public void showAndWait() { 233 show(); 234 while(!done) { 235 try { 236 wait(); 237 } catch (InterruptedException whoCares) {} 238 } 239 } 240 241 242 class BeanProperty { 243 244 private PropertyDescriptor descriptor; 245 246 private PropertyEditor editor; 247 248 public BeanProperty(PropertyDescriptor descriptor) { 249 StringBuffer msg = new StringBuffer(); 250 msg.append("Creating BP from "+descriptor.getDisplayName()); 251 try { 252 this.descriptor = descriptor; 253 //System.out.println(descriptor); 254 this.editor = PropertyEditorManager.findEditor(descriptor.getPropertyType()); 255 msg.append("...found Editor "+editor); 256 257 } 258 catch(Exception e) { 259 e.printStackTrace(); 260 //not a problem - will just not be valid 261 msg.append("- Exception!"); 262 } 263 264 if (verbose) warn(msg.toString()); 265 } 266 267 public PropertyEditor getEditor() { 268 return editor; 269 } 270 public PropertyDescriptor getDescriptor() { 271 return descriptor; 272 } 273 274 275 276 public String getName() { 277 return descriptor.getName(); 278 } 279 280 public void setValueFromBean(Object bean) { 281 Object value = null; 282 try{ 283 Method readMethod = descriptor.getReadMethod(); 284 value = readMethod.invoke(bean,null); 285 } 286 catch (Exception e) { 287 warn("Couldn't read property"); 288 } 289 editor.setValue(value); 290 } 291 292 public boolean isCustom() { 293 if (editor==null) return false; 294 return editor.getCustomEditor()!=null; 295 } 296 public boolean isTagType() { 297 if (editor==null) return false; 298 return editor.getTags()!=null; 299 } 300 301 public void setBeanFromValue(Object bean) { 302 Object value = editor.getValue(); 303 try{ 304 Method writeMethod = descriptor.getWriteMethod(); 305 value = writeMethod.invoke(bean,new Object[] {value}); 306 } 307 catch (Exception e) { 308 warn("Couldn't set property",e); 309 } 310 } 311 312 public boolean isValid() { 313 314 PropertyEditor p = getEditor(); 315 if (p==null || getDescriptor()==null) return false; 316 317 try{ 318 319 320 321 if (descriptor.getWriteMethod()==null) return false; 322 if (descriptor.getReadMethod()==null) return false; 323 } 324 catch( Exception e ) { 325 warn("Exception " + e);e.printStackTrace(); 326 return false; 327 } 328 return true; 329 } 330 331 } 332 333 /*** Getter for property bean. 334 * @return Value of property bean. 335 */ 336 public Object getBean() { 337 return bean; 338 } 339 340 /*** Setter for property bean. 341 * @param bean New value of property bean. 342 */ 343 public void setBean(Object bean) { 344 this.bean = bean; 345 populate(); 346 pack(); 347 invalidate(); 348 349 } 350 351 /*** Getter for property title. 352 * @return Value of property title. 353 */ 354 public String getTitle() { 355 return titleLabel.getText(); 356 } 357 358 /*** Setter for property title. 359 * <BR> 360 * You don't want to be stuck with my title now do you? 361 * @param title New value of property title. 362 */ 363 public void setTitle(String title) { 364 titleLabel.setText(title); 365 } 366 367 // Variables declaration - do not modify//GEN-BEGIN:variables 368 private java.awt.Label titleLabel; 369 private java.awt.ScrollPane scrollPane1; 370 private java.awt.Panel panel1; 371 private java.awt.Panel panel2; 372 private java.awt.Button OKBtn; 373 private java.awt.Button CancelBtn; 374 private java.awt.Button Apply; 375 // End of variables declaration//GEN-END:variables 376 377 378 private Vector propDescsWithEditors = new Vector(); 379 380 /*** Holds value of property foreground. */ 381 private Color foreground; 382 383 /*** Holds value of property font. */ 384 private Font font; 385 386 /*** Holds value of property followInheritanceTree. */ 387 private boolean followInheritanceTree=false; 388 389 /*** Holds value of property verbose. */ 390 private boolean verbose = false; 391 392 private boolean processNames = true; 393 public boolean getProcessNames() { 394 return processNames; 395 } 396 /*** 397 * Attempts to make the labels more attractive by 398 * parsing the names. "_" become spaces, words are broken at 399 * capitals etc. 400 */ 401 public void setProcessNames(boolean processNames) { 402 this.processNames = processNames; 403 } 404 405 private String parseName(String raw) { 406 if (!processNames) return raw; 407 raw = raw.replace('_', ' '); 408 boolean lastWasLower = Character.isLowerCase(raw.charAt(0)); 409 StringBuffer sb = new StringBuffer(); 410 sb.append(Character.toUpperCase(raw.charAt(0))); 411 for (int i=1; i<raw.length(); ++i) { 412 boolean isLower = Character.isLowerCase(raw.charAt(i)); 413 if (lastWasLower && !isLower) { 414 sb.append(' ').append(raw.charAt(i)); 415 } 416 else { 417 sb.append(raw.charAt(i)); 418 } 419 lastWasLower = isLower; 420 } 421 return sb.toString(); 422 } 423 424 private void populate() { 425 try{ 426 BeanInfo beanInfo; 427 if (followInheritanceTree) { 428 beanInfo= Introspector.getBeanInfo(bean.getClass()); 429 } 430 else { 431 beanInfo = Introspector.getBeanInfo(bean.getClass(),bean.getClass().getSuperclass()); 432 } 433 434 PropertyDescriptor[] allPropDescs = beanInfo.getPropertyDescriptors(); 435 propDescsWithEditors.removeAllElements(); 436 437 for (int i=0;i<allPropDescs.length;++i) { 438 BeanProperty bp = new BeanProperty(allPropDescs[i]); 439 if (bp.isValid()) propDescsWithEditors.addElement(bp); 440 } 441 442 443 panel1.setLayout(new GridLayout(propDescsWithEditors.size(),2)); 444 445 Enumeration en = propDescsWithEditors.elements(); 446 while (en.hasMoreElements()) { 447 BeanProperty bp = (BeanProperty) en.nextElement(); 448 bp.setValueFromBean(bean); 449 Label l = new Label(parseName(bp.getName())); 450 panel1.add(l); 451 Component e ; 452 if (bp.isCustom()) { 453 e = new PaintableEditor(bp.getEditor(),this); 454 } 455 else if (bp.isTagType()){ 456 e = new TagEditor(bp.getEditor(), this); 457 } 458 else { 459 e = new StringEditor(bp.getEditor(), this); 460 } 461 panel1.add(e); 462 } 463 464 Dimension d = panel1.getPreferredSize(); 465 d.width+=20; //add a bit for good measure 466 d.height+=20; 467 scrollPane1.setSize(d); 468 } 469 catch (Exception e) { 470 warn("Couldn't populate properties",e); 471 //e.printStackTrace(); 472 dispose(); 473 } 474 475 } 476 477 478 private Vector errors = new Vector(); 479 /*** Returns the last warning posted when creating the dialog - @see getErrors() 480 * @return Last error posted 481 * 482 */ 483 public String getLastError() { 484 return (String) errors.elementAt(errors.size()-1); 485 } 486 /*** As properties are added to the sheet certain exceptions and warnings may 487 * arise. This method allows you to inspect them. 488 * @return A <CODE>List</CODE> containing all the posted warnings. 489 */ 490 public Vector getErrors() { 491 return errors; 492 } 493 494 protected void warn(java.lang.String msg, Exception e) { 495 496 errors.addElement(msg + e.getMessage()); 497 498 } 499 protected void warn(java.lang.String msg) { 500 errors.addElement(msg); 501 } 502 503 /*** Getter for property background. 504 * @return Value of property background. 505 */ 506 public Color getBackground() { 507 return super.getBackground(); 508 } 509 510 /*** Setter for property background. 511 * @param background New value of property background. 512 */ 513 public void setBackground(Color background) { 514 super.setBackground(background); 515 // RecurseComponents.recurse(this,new BackgroundFn(background)); 516 } 517 518 /*** Getter for property foreground. 519 * @return Value of property foreground. 520 */ 521 public Color getForeground() { 522 return super.getForeground(); 523 } 524 525 /*** Setter for property foreground. 526 * @param foreground New value of property foreground. 527 */ 528 public void setForeground(Color foreground) { 529 super.setForeground(foreground); 530 // RecurseComponents.recurse(this,new ForegroundFn(foreground)); 531 } 532 533 /*** Getter for property font. 534 * @return Value of property font. 535 */ 536 public Font getFont() { 537 return super.getFont(); 538 } 539 540 /*** Setter for property font. 541 * @param font New value of property font. 542 */ 543 public void setFont(Font font) { 544 super.setFont(font); 545 //RecurseComponents.recurse(this,new FontFn(font)); 546 } 547 548 /*** Getter for property paintAreaSize. 549 * @return Value of property paintAreaSize. 550 */ 551 public Dimension getPaintAreaSize() { 552 return PaintableEditor.getPaintArea(); 553 } 554 555 /*** Setter for property paintAreaSize. 556 * @param paintAreaSize New value of property paintAreaSize. 557 */ 558 public void setPaintAreaSize(Dimension paintAreaSize) { 559 PaintableEditor.setPaintArea(paintAreaSize); 560 } 561 562 /*** Getter for property verbose. 563 * @return Value of property verbose. 564 */ 565 public boolean isVerbose() { 566 return verbose; 567 } 568 569 /*** Setter for property verbose. 570 * @param verbose New value of property verbose. 571 */ 572 public void setVerbose(boolean verbose) { 573 this.verbose = verbose; 574 } 575 576 /*** Getter for property followInheritanceTree. 577 * @return Value of property followInheritanceTree. 578 */ 579 public boolean isFollowInheritanceTree() { 580 return followInheritanceTree; 581 } 582 583 /*** Setter for property followInheritanceTree. 584 * @param followInheritanceTree New value of property followInheritanceTree. 585 */ 586 public void setFollowInheritanceTree(boolean followInheritanceTree) { 587 this.followInheritanceTree = followInheritanceTree; 588 } 589 590 /*** 591 * The bean we're editing has changed.... 592 */ 593 public void propertyChange(java.beans.PropertyChangeEvent propertyChangeEvent) { 594 refresh(); 595 } 596 597 598 599 }

This page was automatically generated by Maven