[29] | 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 | |
---|
| 24 | package weka.gui; |
---|
| 25 | |
---|
| 26 | import weka.core.Capabilities; |
---|
| 27 | import weka.core.CapabilitiesHandler; |
---|
| 28 | import weka.core.MultiInstanceCapabilitiesHandler; |
---|
| 29 | |
---|
| 30 | import java.awt.BorderLayout; |
---|
| 31 | import java.awt.Component; |
---|
| 32 | import java.awt.Dialog; |
---|
| 33 | import java.awt.Dimension; |
---|
| 34 | import java.awt.Font; |
---|
| 35 | import java.awt.Frame; |
---|
| 36 | import java.awt.GridBagConstraints; |
---|
| 37 | import java.awt.GridBagLayout; |
---|
| 38 | import java.awt.Insets; |
---|
| 39 | import java.awt.event.ActionEvent; |
---|
| 40 | import java.awt.event.ActionListener; |
---|
| 41 | import java.awt.event.WindowAdapter; |
---|
| 42 | import java.awt.event.WindowEvent; |
---|
| 43 | import java.beans.BeanInfo; |
---|
| 44 | import java.beans.Beans; |
---|
| 45 | import java.beans.IntrospectionException; |
---|
| 46 | import java.beans.Introspector; |
---|
| 47 | import java.beans.MethodDescriptor; |
---|
| 48 | import java.beans.PropertyChangeEvent; |
---|
| 49 | import java.beans.PropertyChangeListener; |
---|
| 50 | import java.beans.PropertyChangeSupport; |
---|
| 51 | import java.beans.PropertyDescriptor; |
---|
| 52 | import java.beans.PropertyEditor; |
---|
| 53 | import java.beans.PropertyEditorManager; |
---|
| 54 | import java.beans.PropertyVetoException; |
---|
| 55 | import java.lang.reflect.InvocationTargetException; |
---|
| 56 | import java.lang.reflect.Method; |
---|
| 57 | import java.util.Iterator; |
---|
| 58 | |
---|
| 59 | import javax.swing.BorderFactory; |
---|
| 60 | import javax.swing.JButton; |
---|
| 61 | import javax.swing.JComponent; |
---|
| 62 | import javax.swing.JDialog; |
---|
| 63 | import javax.swing.JFrame; |
---|
| 64 | import javax.swing.JLabel; |
---|
| 65 | import javax.swing.JOptionPane; |
---|
| 66 | import javax.swing.JPanel; |
---|
| 67 | import javax.swing.JScrollPane; |
---|
| 68 | import javax.swing.JTextArea; |
---|
| 69 | import 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 | */ |
---|
| 79 | public 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 | |
---|