source: src/main/java/weka/gui/PropertySheetPanel.java @ 5

Last change on this file since 5 was 4, checked in by gnappo, 14 years ago

Import di weka.

File size: 26.3 KB
Line 
1/*
2 *    This program is free software; you can redistribute it and/or modify
3 *    it under the terms of the GNU General Public License as published by
4 *    the Free Software Foundation; either version 2 of the License, or
5 *    (at your option) any later version.
6 *
7 *    This program is distributed in the hope that it will be useful,
8 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 *    GNU General Public License for more details.
11 *
12 *    You should have received a copy of the GNU General Public License
13 *    along with this program; if not, write to the Free Software
14 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 */
16
17/*
18 *    PropertySheet.java
19 *    Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23
24package weka.gui;
25
26import weka.core.Capabilities;
27import weka.core.CapabilitiesHandler;
28import weka.core.MultiInstanceCapabilitiesHandler;
29
30import java.awt.BorderLayout;
31import java.awt.Component;
32import java.awt.Dialog;
33import java.awt.Dimension;
34import java.awt.Font;
35import java.awt.Frame;
36import java.awt.GridBagConstraints;
37import java.awt.GridBagLayout;
38import java.awt.Insets;
39import java.awt.event.ActionEvent;
40import java.awt.event.ActionListener;
41import java.awt.event.WindowAdapter;
42import java.awt.event.WindowEvent;
43import java.beans.BeanInfo;
44import java.beans.Beans;
45import java.beans.IntrospectionException;
46import java.beans.Introspector;
47import java.beans.MethodDescriptor;
48import java.beans.PropertyChangeEvent;
49import java.beans.PropertyChangeListener;
50import java.beans.PropertyChangeSupport;
51import java.beans.PropertyDescriptor;
52import java.beans.PropertyEditor;
53import java.beans.PropertyEditorManager;
54import java.beans.PropertyVetoException;
55import java.lang.reflect.InvocationTargetException;
56import java.lang.reflect.Method;
57import java.util.Iterator;
58
59import javax.swing.BorderFactory;
60import javax.swing.JButton;
61import javax.swing.JComponent;
62import javax.swing.JDialog;
63import javax.swing.JFrame;
64import javax.swing.JLabel;
65import javax.swing.JOptionPane;
66import javax.swing.JPanel;
67import javax.swing.JScrollPane;
68import javax.swing.JTextArea;
69import javax.swing.SwingConstants;
70
71
72/**
73 * Displays a property sheet where (supported) properties of the target
74 * object may be edited.
75 *
76 * @author Len Trigg (trigg@cs.waikato.ac.nz)
77 * @version $Revision: 6097 $
78 */
79public class PropertySheetPanel extends JPanel
80  implements PropertyChangeListener {
81
82  /** for serialization. */
83  private static final long serialVersionUID = -8939835593429918345L;
84
85  /**
86   * A specialized dialog for displaying the capabilities.
87   */
88  protected class CapabilitiesHelpDialog
89    extends JDialog
90    implements PropertyChangeListener {
91   
92    /** for serialization. */
93    private static final long serialVersionUID = -1404770987103289858L;
94   
95    /** the dialog itself. */
96    private CapabilitiesHelpDialog m_Self;
97   
98    /**
99     * default constructor.
100     *
101     * @param owner     the owning frame
102     */
103    public CapabilitiesHelpDialog(Frame owner) {
104      super(owner);
105     
106      initialize();
107    }
108   
109    /**
110     * default constructor.
111     *
112     * @param owner     the owning dialog
113     */
114    public CapabilitiesHelpDialog(Dialog owner) {
115      super(owner);
116     
117      initialize();
118    }
119
120    /**
121     * Initializes the dialog.
122     */
123    protected void initialize() {
124      setTitle("Information about Capabilities");
125
126      m_Self = this;
127     
128      m_CapabilitiesText = new JTextArea();
129      m_CapabilitiesText.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
130      m_CapabilitiesText.setLineWrap(true);
131      m_CapabilitiesText.setWrapStyleWord(true);
132      m_CapabilitiesText.setEditable(false);
133      updateText();
134      addWindowListener(new WindowAdapter() {
135        public void windowClosing(WindowEvent e) {
136          m_Self.dispose();
137          if (m_CapabilitiesDialog == m_Self) {
138            m_CapabilitiesBut.setEnabled(true);
139          }
140        }
141      });
142      getContentPane().setLayout(new BorderLayout());
143      getContentPane().add(new JScrollPane(m_CapabilitiesText), BorderLayout.CENTER);
144      pack();
145    }
146
147    /**
148     * returns a comma-separated list of all the capabilities.
149     *
150     * @param c         the capabilities to get a string representation from
151     * @return          the string describing the capabilities
152     */
153    protected String listCapabilities(Capabilities c) {
154      String    result;
155      Iterator  iter;
156     
157      result = "";
158      iter   = c.capabilities();
159      while (iter.hasNext()) {
160        if (result.length() != 0)
161        result += ", ";
162        result += iter.next().toString();
163      }
164     
165      return result;
166    }
167   
168    /**
169     * generates a string from the capapbilities, suitable to add to the help
170     * text.
171     *
172     * @param title     the title for the capabilities
173     * @param c         the capabilities
174     * @return          a string describing the capabilities
175     */
176    protected String addCapabilities(String title, Capabilities c) {
177      String            result;
178      String            caps;
179     
180      result = title + "\n";
181     
182      // class
183      caps = listCapabilities(c.getClassCapabilities());
184      if (caps.length() != 0) {
185        result += "Class -- ";
186        result += caps;
187        result += "\n\n";
188      }
189     
190      // attribute
191      caps = listCapabilities(c.getAttributeCapabilities());
192      if (caps.length() != 0) {
193        result += "Attributes -- ";
194        result += caps;
195        result += "\n\n";
196      }
197     
198      // other capabilities
199      caps = listCapabilities(c.getOtherCapabilities());
200      if (caps.length() != 0) {
201        result += "Other -- ";
202        result += caps;
203        result += "\n\n";
204      }
205     
206      // additional stuff
207      result += "Additional\n";
208      result += "min # of instances: " + c.getMinimumNumberInstances() + "\n";
209      result += "\n";
210     
211      return result;
212    } 
213
214    /**
215     * updates the content of the capabilities help dialog.
216     */
217    protected void updateText() {
218      StringBuffer helpText = new StringBuffer();
219     
220      if (m_Target instanceof CapabilitiesHandler)
221        helpText.append(
222          addCapabilities(
223              "CAPABILITIES", 
224              ((CapabilitiesHandler) m_Target).getCapabilities()));
225     
226      if (m_Target instanceof MultiInstanceCapabilitiesHandler)
227        helpText.append(
228          addCapabilities(
229              "MI CAPABILITIES", 
230              ((MultiInstanceCapabilitiesHandler) m_Target).getMultiInstanceCapabilities()));
231     
232      m_CapabilitiesText.setText(helpText.toString());
233      m_CapabilitiesText.setCaretPosition(0);
234    }
235   
236    /**
237     * This method gets called when a bound property is changed.
238     * 
239     * @param evt       the change event
240     */
241    public void propertyChange(PropertyChangeEvent evt) {
242      updateText();
243    }
244  }
245 
246  /** The target object being edited. */
247  private Object m_Target;
248
249  /** Holds properties of the target. */
250  private PropertyDescriptor m_Properties[];
251
252  /** Holds the methods of the target. */
253  private MethodDescriptor m_Methods[];
254
255  /** Holds property editors of the object. */
256  private PropertyEditor m_Editors[];
257
258  /** Holds current object values for each property. */
259  private Object m_Values[];
260
261  /** Stores GUI components containing each editing component. */
262  private JComponent m_Views[];
263
264  /** The labels for each property. */
265  private JLabel m_Labels[];
266
267  /** The tool tip text for each property. */
268  private String m_TipTexts[];
269
270  /** StringBuffer containing help text for the object being edited. */
271  private StringBuffer m_HelpText;
272
273  /** Help dialog. */
274  private JDialog m_HelpDialog;
275
276  /** Capabilities Help dialog. */
277  private CapabilitiesHelpDialog m_CapabilitiesDialog;
278
279  /** Button to pop up the full help text in a separate dialog. */
280  private JButton m_HelpBut;
281
282  /** Button to pop up the capabilities in a separate dialog. */
283  private JButton m_CapabilitiesBut;
284 
285  /** the TextArea of the Capabilities help dialog. */
286  private JTextArea m_CapabilitiesText;
287
288  /** A count of the number of properties we have an editor for. */
289  private int m_NumEditable = 0;
290
291  /** The panel holding global info and help, if provided by
292      the object being editied. */
293  private JPanel m_aboutPanel;
294
295  /**
296   * Creates the property sheet panel.
297   */
298  public PropertySheetPanel() {
299
300    //    setBorder(BorderFactory.createLineBorder(Color.red));
301    setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0));
302  }
303
304  /**
305   * Return the panel containing global info and help for
306   * the object being edited. May return null if the edited
307   * object provides no global info or tip text.
308   *
309   * @return the about panel.
310   */
311  public JPanel getAboutPanel() {
312    return m_aboutPanel;
313  }
314
315  /** A support object for handling property change listeners. */ 
316  private PropertyChangeSupport support = new PropertyChangeSupport(this);
317
318  /**
319   * Updates the property sheet panel with a changed property and also passed
320   * the event along.
321   *
322   * @param evt a value of type 'PropertyChangeEvent'
323   */
324  public void propertyChange(PropertyChangeEvent evt) {
325    wasModified(evt); // Let our panel update before guys downstream
326    support.firePropertyChange("", null, null);
327  }
328
329  /**
330   * Adds a PropertyChangeListener.
331   *
332   * @param l a value of type 'PropertyChangeListener'
333   */
334  public void addPropertyChangeListener(PropertyChangeListener l) {
335    support.addPropertyChangeListener(l);
336  }
337
338  /**
339   * Removes a PropertyChangeListener.
340   *
341   * @param l a value of type 'PropertyChangeListener'
342   */
343  public void removePropertyChangeListener(PropertyChangeListener l) {
344    support.removePropertyChangeListener(l);
345  }
346 
347  /**
348   * Sets a new target object for customisation.
349   *
350   * @param targ a value of type 'Object'
351   */
352  public synchronized void setTarget(Object targ) {
353
354    // used to offset the components for the properties of targ
355    // if there happens to be globalInfo available in targ
356    int componentOffset = 0;
357
358    // Close any child windows at this point
359    removeAll();
360
361    setLayout(new BorderLayout());
362    JPanel scrollablePanel = new JPanel();
363    JScrollPane scrollPane = new JScrollPane(scrollablePanel);
364    scrollPane.setBorder(BorderFactory.createEmptyBorder());
365    add(scrollPane, BorderLayout.CENTER);
366   
367    GridBagLayout gbLayout = new GridBagLayout();
368
369    scrollablePanel.setLayout(gbLayout);
370    setVisible(false);
371    m_NumEditable = 0;
372    m_Target = targ;
373    try {
374      BeanInfo bi = Introspector.getBeanInfo(m_Target.getClass());
375      m_Properties = bi.getPropertyDescriptors();
376      m_Methods = bi.getMethodDescriptors();
377    } catch (IntrospectionException ex) {
378      System.err.println("PropertySheet: Couldn't introspect");
379      return;
380    }
381
382    JTextArea jt = new JTextArea();
383    m_HelpText = null;
384    // Look for a globalInfo method that returns a string
385    // describing the target
386    for (int i = 0;i < m_Methods.length; i++) {
387      String name = m_Methods[i].getDisplayName();
388      Method meth = m_Methods[i].getMethod();
389      if (name.equals("globalInfo")) {
390        if (meth.getReturnType().equals(String.class)) {
391          try {
392            Object args[] = { };
393            String globalInfo = (String)(meth.invoke(m_Target, args));
394            String summary = globalInfo;
395            int ci = globalInfo.indexOf('.');
396            if (ci != -1) {
397              summary = globalInfo.substring(0, ci + 1);
398            }
399            final String className = targ.getClass().getName();
400            m_HelpText = new StringBuffer("NAME\n");
401            m_HelpText.append(className).append("\n\n");
402            m_HelpText.append("SYNOPSIS\n").append(globalInfo).append("\n\n");
403            m_HelpBut = new JButton("More");
404            m_HelpBut.setToolTipText("More information about "
405                                     + className);
406           
407            m_HelpBut.addActionListener(new ActionListener() {
408              public void actionPerformed(ActionEvent a) {
409                openHelpFrame();
410                m_HelpBut.setEnabled(false);
411              }
412            });
413
414            if (m_Target instanceof CapabilitiesHandler) {
415              m_CapabilitiesBut = new JButton("Capabilities");
416              m_CapabilitiesBut.setToolTipText("The capabilities of "
417                  + className);
418             
419              m_CapabilitiesBut.addActionListener(new ActionListener() {
420                public void actionPerformed(ActionEvent a) {
421                  openCapabilitiesHelpDialog();
422                  m_CapabilitiesBut.setEnabled(false);
423                }
424              });
425            }
426            else {
427              m_CapabilitiesBut = null;
428            }
429
430            jt.setColumns(30);
431            jt.setFont(new Font("SansSerif", Font.PLAIN,12));
432            jt.setEditable(false);
433            jt.setLineWrap(true);
434            jt.setWrapStyleWord(true);
435            jt.setText(summary);
436            jt.setBackground(getBackground());
437            JPanel jp = new JPanel();
438            jp.setBorder(BorderFactory.createCompoundBorder(
439                         BorderFactory.createTitledBorder("About"),
440                         BorderFactory.createEmptyBorder(5, 5, 5, 5)
441                 ));
442            jp.setLayout(new BorderLayout());
443            jp.add(jt, BorderLayout.CENTER);
444            JPanel p2 = new JPanel();
445            p2.setLayout(new BorderLayout());
446            p2.add(m_HelpBut, BorderLayout.NORTH);
447            if (m_CapabilitiesBut != null) {
448              JPanel p3 = new JPanel();
449              p3.setLayout(new BorderLayout());
450              p3.add(m_CapabilitiesBut, BorderLayout.NORTH);
451              p2.add(p3, BorderLayout.CENTER);
452            }
453            jp.add(p2, BorderLayout.EAST);
454            GridBagConstraints gbConstraints = new GridBagConstraints();
455            //      gbConstraints.anchor = GridBagConstraints.EAST;
456            gbConstraints.fill = GridBagConstraints.BOTH;
457            //      gbConstraints.gridy = 0;     gbConstraints.gridx = 0;
458            gbConstraints.gridwidth = 2;
459            gbConstraints.insets = new Insets(0,5,0,5);
460            gbLayout.setConstraints(jp, gbConstraints);
461            m_aboutPanel = jp;
462            scrollablePanel.add(m_aboutPanel);
463            componentOffset = 1;
464            break;
465          } catch (Exception ex) {
466           
467          }
468        }
469      }
470    }
471
472    m_Editors = new PropertyEditor[m_Properties.length];
473    m_Values = new Object[m_Properties.length];
474    m_Views = new JComponent[m_Properties.length];
475    m_Labels = new JLabel[m_Properties.length];
476    m_TipTexts = new String[m_Properties.length];
477    boolean firstTip = true;
478    for (int i = 0; i < m_Properties.length; i++) {
479
480      // Don't display hidden or expert properties.
481      if (m_Properties[i].isHidden() || m_Properties[i].isExpert()) {
482        continue;
483      }
484
485      String name = m_Properties[i].getDisplayName();
486      Class type = m_Properties[i].getPropertyType();
487      Method getter = m_Properties[i].getReadMethod();
488      Method setter = m_Properties[i].getWriteMethod();
489
490      // Only display read/write properties.
491      if (getter == null || setter == null) {
492        continue;
493      }
494       
495      JComponent view = null;
496
497      try {
498        Object args[] = { };
499        Object value = getter.invoke(m_Target, args);
500        m_Values[i] = value;
501
502        PropertyEditor editor = null;
503        Class pec = m_Properties[i].getPropertyEditorClass();
504        if (pec != null) {
505          try {
506            editor = (PropertyEditor)pec.newInstance();
507          } catch (Exception ex) {
508            // Drop through.
509          }
510        }
511        if (editor == null) {
512          editor = PropertyEditorManager.findEditor(type);
513        }
514        m_Editors[i] = editor;
515
516        // If we can't edit this component, skip it.
517        if (editor == null) {
518          // If it's a user-defined property we give a warning.
519          String getterClass = m_Properties[i].getReadMethod()
520            .getDeclaringClass().getName();
521          /*
522          if (getterClass.indexOf("java.") != 0) {
523            System.err.println("Warning: Can't find public property editor"
524                               + " for property \"" + name + "\" (class \""
525                               + type.getName() + "\").  Skipping.");
526          }
527          */
528          continue;
529        }
530        if (editor instanceof GenericObjectEditor) {
531          ((GenericObjectEditor) editor).setClassType(type);
532        }
533
534        // Don't try to set null values:
535        if (value == null) {
536          // If it's a user-defined property we give a warning.
537          String getterClass = m_Properties[i].getReadMethod()
538            .getDeclaringClass().getName();
539          /*
540          if (getterClass.indexOf("java.") != 0) {
541            System.err.println("Warning: Property \"" + name
542                               + "\" has null initial value.  Skipping.");
543          }
544          */
545          continue;
546        }
547
548        editor.setValue(value);
549
550        // now look for a TipText method for this property
551        String tipName = name + "TipText";
552        for (int j = 0; j < m_Methods.length; j++) {
553          String mname = m_Methods[j].getDisplayName();
554          Method meth = m_Methods[j].getMethod();
555          if (mname.equals(tipName)) {
556            if (meth.getReturnType().equals(String.class)) {
557              try {
558                String tempTip = (String)(meth.invoke(m_Target, args));
559                int ci = tempTip.indexOf('.');
560                if (ci < 0) {
561                  m_TipTexts[i] = tempTip;
562                } else {
563                  m_TipTexts[i] = tempTip.substring(0, ci);
564                }
565                if (m_HelpText != null) {
566                  if (firstTip) {
567                    m_HelpText.append("OPTIONS\n");
568                    firstTip = false;
569                  }
570                  m_HelpText.append(name).append(" -- ");
571                  m_HelpText.append(tempTip).append("\n\n");
572                  //jt.setText(m_HelpText.toString());
573                }
574              } catch (Exception ex) {
575
576              }
577              break;
578            }
579          }
580        }         
581
582        // Now figure out how to display it...
583        if (editor.isPaintable() && editor.supportsCustomEditor()) {
584          view = new PropertyPanel(editor);
585        } else if (editor.supportsCustomEditor() && (editor.getCustomEditor() instanceof JComponent)) {
586          view = (JComponent) editor.getCustomEditor();
587        } else if (editor.getTags() != null) {
588          view = new PropertyValueSelector(editor);
589        } else if (editor.getAsText() != null) {
590          view = new PropertyText(editor);
591        } else {
592          System.err.println("Warning: Property \"" + name
593                             + "\" has non-displayabale editor.  Skipping.");
594          continue;
595        }
596       
597        editor.addPropertyChangeListener(this);
598
599      } catch (InvocationTargetException ex) {
600        System.err.println("Skipping property " + name
601                           + " ; exception on target: "
602                           + ex.getTargetException());
603        ex.getTargetException().printStackTrace();
604        continue;
605      } catch (Exception ex) {
606        System.err.println("Skipping property " + name
607                           + " ; exception: " + ex);
608        ex.printStackTrace();
609        continue;
610      }
611
612      m_Labels[i] = new JLabel(name, SwingConstants.RIGHT);
613      m_Labels[i].setBorder(BorderFactory.createEmptyBorder(10, 10, 0, 5));
614      m_Views[i] = view;
615      GridBagConstraints gbConstraints = new GridBagConstraints();
616      gbConstraints.anchor = GridBagConstraints.EAST;
617      gbConstraints.fill = GridBagConstraints.HORIZONTAL;
618      gbConstraints.gridy = i+componentOffset;     gbConstraints.gridx = 0;
619      gbLayout.setConstraints(m_Labels[i], gbConstraints);
620      scrollablePanel.add(m_Labels[i]);
621      JPanel newPanel = new JPanel();
622      if (m_TipTexts[i] != null) {
623        m_Views[i].setToolTipText(m_TipTexts[i]);
624      }
625      newPanel.setBorder(BorderFactory.createEmptyBorder(10, 5, 0, 10));
626      newPanel.setLayout(new BorderLayout());
627      newPanel.add(m_Views[i], BorderLayout.CENTER);
628      gbConstraints = new GridBagConstraints();
629      gbConstraints.anchor = GridBagConstraints.WEST;
630      gbConstraints.fill = GridBagConstraints.BOTH;
631      gbConstraints.gridy = i+componentOffset;     gbConstraints.gridx = 1;
632      gbConstraints.weightx = 100;
633      gbLayout.setConstraints(newPanel, gbConstraints);
634      scrollablePanel.add(newPanel);
635      m_NumEditable ++;
636    }
637
638    if (m_NumEditable == 0) {
639      JLabel empty = new JLabel("No editable properties", 
640                                SwingConstants.CENTER);
641      Dimension d = empty.getPreferredSize();
642      empty.setPreferredSize(new Dimension(d.width * 2, d.height * 2));
643      empty.setBorder(BorderFactory.createEmptyBorder(10, 5, 0, 10));
644      GridBagConstraints gbConstraints = new GridBagConstraints();
645      gbConstraints.anchor = GridBagConstraints.CENTER;
646      gbConstraints.fill = GridBagConstraints.HORIZONTAL;
647      gbConstraints.gridy = componentOffset;     gbConstraints.gridx = 0;
648      gbLayout.setConstraints(empty, gbConstraints);
649      scrollablePanel.add(empty);
650    }
651
652    validate();
653
654    // sometimes, the calculated dimensions seem to be too small and the
655    // scrollbars show up, though there is still plenty of space on the
656    // screen. hence we increase the dimensions a bit to fix this.
657    Dimension dim = scrollablePanel.getPreferredSize();
658    dim.height += 20;
659    dim.width  += 20;
660    scrollPane.setPreferredSize(dim);
661    validate();
662
663    setVisible(true);   
664  }
665
666  /**
667   * opens the help dialog.
668   */
669  protected void openHelpFrame() {
670
671    JTextArea ta = new JTextArea();
672    ta.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
673    ta.setLineWrap(true);
674    ta.setWrapStyleWord(true);
675    //ta.setBackground(getBackground());
676    ta.setEditable(false);
677    ta.setText(m_HelpText.toString());
678    ta.setCaretPosition(0);
679    JDialog jdtmp;
680    if (PropertyDialog.getParentDialog(this) != null)
681      jdtmp = new JDialog(PropertyDialog.getParentDialog(this), "Information");
682    else
683      jdtmp = new JDialog(PropertyDialog.getParentFrame(this), "Information");
684    final JDialog jd = jdtmp;
685    jd.addWindowListener(new WindowAdapter() {
686      public void windowClosing(WindowEvent e) {
687        jd.dispose();
688        if (m_HelpDialog == jd) {
689          m_HelpBut.setEnabled(true);
690        }
691      }
692    });
693    jd.getContentPane().setLayout(new BorderLayout());
694    jd.getContentPane().add(new JScrollPane(ta), BorderLayout.CENTER);
695    jd.pack();
696    jd.setSize(400, 350);
697    jd.setLocation(m_aboutPanel.getTopLevelAncestor().getLocationOnScreen().x 
698                   + m_aboutPanel.getTopLevelAncestor().getSize().width,
699                   m_aboutPanel.getTopLevelAncestor().getLocationOnScreen().y);
700    jd.setVisible(true);
701    m_HelpDialog = jd;
702  }
703 
704  /**
705   * opens the help dialog for the capabilities.
706   */
707  protected void openCapabilitiesHelpDialog() {
708    if (PropertyDialog.getParentDialog(this) != null)
709      m_CapabilitiesDialog = new CapabilitiesHelpDialog(PropertyDialog.getParentDialog(this));
710    else
711      m_CapabilitiesDialog = new CapabilitiesHelpDialog(PropertyDialog.getParentFrame(this));
712    m_CapabilitiesDialog.setSize(400, 350);
713    m_CapabilitiesDialog.setLocation(m_aboutPanel.getTopLevelAncestor().getLocationOnScreen().x 
714                   + m_aboutPanel.getTopLevelAncestor().getSize().width,
715                   m_aboutPanel.getTopLevelAncestor().getLocationOnScreen().y);
716    m_CapabilitiesDialog.setVisible(true);
717    addPropertyChangeListener(m_CapabilitiesDialog);
718  }
719
720  /**
721   * Gets the number of editable properties for the current target.
722   *
723   * @return the number of editable properties.
724   */
725  public int editableProperties() {
726
727    return m_NumEditable;
728  }
729 
730  /**
731   * Updates the propertysheet when a value has been changed (from outside
732   * the propertysheet?).
733   *
734   * @param evt a value of type 'PropertyChangeEvent'
735   */
736  synchronized void wasModified(PropertyChangeEvent evt) {
737
738    //    System.err.println("wasModified");
739    if (evt.getSource() instanceof PropertyEditor) {
740      PropertyEditor editor = (PropertyEditor) evt.getSource();
741      for (int i = 0 ; i < m_Editors.length; i++) {
742        if (m_Editors[i] == editor) {
743          PropertyDescriptor property = m_Properties[i];
744          Object value = editor.getValue();
745          m_Values[i] = value;
746          Method setter = property.getWriteMethod();
747          try {
748            Object args[] = { value };
749            args[0] = value;
750            setter.invoke(m_Target, args);
751          } catch (InvocationTargetException ex) {
752            if (ex.getTargetException()
753                instanceof PropertyVetoException) {
754              String message = "WARNING: Vetoed; reason is: " 
755                               + ex.getTargetException().getMessage();
756              System.err.println(message);
757             
758              Component jf;
759              if(evt.getSource() instanceof JPanel)
760                  jf = ((JPanel)evt.getSource()).getParent();
761              else
762                  jf = new JFrame();
763              JOptionPane.showMessageDialog(jf, message, 
764                                            "error", 
765                                            JOptionPane.WARNING_MESSAGE);
766              if(jf instanceof JFrame)
767                  ((JFrame)jf).dispose();
768
769            } else {
770              System.err.println(ex.getTargetException().getClass().getName()+ 
771                                 " while updating "+ property.getName() +": "+
772                                 ex.getTargetException().getMessage());
773              Component jf;
774              if(evt.getSource() instanceof JPanel)
775                  jf = ((JPanel)evt.getSource()).getParent();
776              else
777                  jf = new JFrame();
778              JOptionPane.showMessageDialog(jf,
779                                            ex.getTargetException().getClass().getName()+ 
780                                            " while updating "+ property.getName()+
781                                            ":\n"+
782                                            ex.getTargetException().getMessage(), 
783                                            "error", 
784                                            JOptionPane.WARNING_MESSAGE);
785              if(jf instanceof JFrame)
786                  ((JFrame)jf).dispose();
787
788            }
789          } catch (Exception ex) {
790            System.err.println("Unexpected exception while updating " 
791                  + property.getName());
792          }
793          if (m_Views[i] != null && m_Views[i] instanceof PropertyPanel) {
794            //System.err.println("Trying to repaint the property canvas");
795            m_Views[i].repaint();
796            revalidate();
797          }
798          break;
799        }
800      }
801    }
802
803    // Now re-read all the properties and update the editors
804    // for any other properties that have changed.
805    for (int i = 0; i < m_Properties.length; i++) {
806      Object o;
807      try {
808        Method getter = m_Properties[i].getReadMethod();
809        Method setter = m_Properties[i].getWriteMethod();
810       
811        if (getter == null || setter == null) {
812          // ignore set/get only properties
813          continue;
814        }
815
816        Object args[] = { };
817        o = getter.invoke(m_Target, args);
818      } catch (Exception ex) {
819        o = null;
820      }
821      if (o == m_Values[i] || (o != null && o.equals(m_Values[i]))) {
822        // The property is equal to its old value.
823        continue;
824      }
825      m_Values[i] = o;
826      // Make sure we have an editor for this property...
827      if (m_Editors[i] == null) {
828        continue;
829      }
830      // The property has changed!  Update the editor.
831      m_Editors[i].removePropertyChangeListener(this);
832      m_Editors[i].setValue(o);
833      m_Editors[i].addPropertyChangeListener(this);
834      if (m_Views[i] != null) {
835        //System.err.println("Trying to repaint " + (i + 1));
836        m_Views[i].repaint();
837      }
838    }
839
840    // Make sure the target bean gets repainted.
841    if (Beans.isInstanceOf(m_Target, Component.class)) {
842      ((Component)(Beans.getInstanceOf(m_Target, Component.class))).repaint();
843    }
844  }
845}
846
847
Note: See TracBrowser for help on using the repository browser.