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