1 19 20 package org.openide.explorer.propertysheet; 21 22 import java.awt.BorderLayout ; 23 import java.awt.BorderLayout ; 24 import java.awt.Color ; 25 import java.awt.Component ; 26 import java.awt.Container ; 27 import java.awt.Dimension ; 28 import java.awt.FlowLayout ; 29 import java.awt.Graphics ; 30 import java.awt.KeyboardFocusManager ; 31 import javax.swing.JFrame ; 32 import java.util.StringTokenizer ; 33 import java.awt.Point ; 34 import java.awt.Rectangle ; 35 import java.awt.Window ; 36 import org.openide.explorer.propertysheet.PropertySheet; 37 import java.awt.event.ActionEvent ; 38 import java.awt.event.ActionListener ; 39 import java.awt.event.FocusEvent ; 40 import java.awt.event.FocusListener ; 41 import java.awt.event.KeyEvent ; 42 import java.awt.event.MouseEvent ; 43 import java.awt.event.WindowAdapter ; 44 import java.awt.event.WindowEvent ; 45 import java.awt.image.BufferedImage ; 46 import org.openide.*; 47 import org.openide.nodes.*; 48 import org.openide.explorer.propertysheet.*; 49 import org.openide.explorer.propertysheet.editors.*; 50 import java.beans.*; 51 import java.beans.PropertyVetoException ; 52 import java.io.File ; 53 import java.lang.ref.WeakReference ; 54 import java.lang.reflect.*; 55 import javax.swing.*; 56 import javax.swing.ImageIcon ; 57 import javax.swing.JPanel ; 58 import javax.swing.JTextField ; 59 import javax.swing.event.ChangeEvent ; 60 import javax.swing.event.ChangeListener ; 61 import junit.framework.*; 62 import junit.textui.TestRunner; 63 import org.netbeans.junit.*; 64 import org.openide.ErrorManager; 65 import org.openide.util.Lookup; 66 67 68 public class CustomEditorDisplayerTest extends NbTestCase { 69 70 static { 71 ComboTest.registerPropertyEditors(); 72 } 73 74 public CustomEditorDisplayerTest(String name) { 75 super(name); 76 } 77 78 public static void main(String args[]) { 79 86 87 88 TestRunner.run(suite ()); 89 90 91 124 try { 125 } catch (Exception e){} 127 128 } 129 130 static int idx = -1; 131 public static Test suite() { 132 return new CustomEditorDisplayerSuite (); 133 } 134 135 private static class CustomEditorDisplayerSuite extends NbTestSuite { 136 public CustomEditorDisplayerSuite () { 137 super (CustomEditorDisplayerTest.class); 138 } 139 140 public void run (final TestResult tr) { 141 super.run (tr); 142 } 143 } 144 149 150 CustomEditorDisplayer basicRen; 151 CustomEditorDisplayer fileRen; 152 153 private TNode tn; 154 private BasicProperty basicProp; 155 private FileProperty fileProp; 156 private BasicEditor te; 157 158 private boolean setup=false; 159 private JFrame jf=null; 160 private JPanel jp=null; 161 private int SLEEP_LENGTH=10; 162 163 protected void tearDown() { 164 if (jf != null) { 165 jf.hide(); 166 jf.dispose(); 167 } 168 } 169 170 protected void setUp() throws Exception { 171 174 try { 175 if (setup) return; 176 basicProp= new BasicProperty("basicProp", true); 177 fileProp= new FileProperty("FileProp", true); 178 179 te = new BasicEditor(); 181 tn = new TNode(); 183 184 System.err.println("Crating frame"); 185 jf = new JFrame (); 186 jf.getContentPane().setLayout(new BorderLayout ()); 187 jp = new JPanel (); 188 jp.setLayout(new FlowLayout ()); 189 jf.getContentPane().add(jp, BorderLayout.CENTER); 190 jf.setLocation (20,20); 191 jf.setSize (600, 200); 192 193 synchronized (jp.getTreeLock()) { 194 System.err.println("BasicProp = " + basicProp); 195 196 basicRen = new CustomEditorDisplayer(basicProp); 197 fileRen = new CustomEditorDisplayer(fileProp); 198 199 200 jp.add(basicRen.getComponent()); 201 202 jp.add(fileRen.getComponent()); 203 } 204 205 System.err.println("Waiting for window"); 206 new WaitWindow(jf); System.err.println("Window shown"); 208 } catch (Exception e) { 209 e.printStackTrace(); 210 } finally { 211 setup = true; 212 } 213 } 214 215 public void testEntryInCustomEditor() throws Exception { 216 basicRen.setUpdatePolicy(PropertyDisplayer.UPDATE_ON_CONFIRMATION); 218 219 BasicCustomEditor custom = (BasicCustomEditor)basicProp.getPropertyEditor().getCustomEditor(); 220 221 clickOn(custom.valueField); 222 typeKey(custom.valueField, KeyEvent.VK_W); 223 typeKey(custom.valueField, KeyEvent.VK_O); 224 typeKey(custom.valueField, KeyEvent.VK_O); 225 typeKey(custom.valueField, KeyEvent.VK_G); 226 typeKey(custom.valueField, KeyEvent.VK_L); 227 typeKey(custom.valueField, KeyEvent.VK_E); 228 229 Object pre = basicProp.getValue(); 230 231 pressKey(custom.valueField, KeyEvent.VK_ENTER); 232 233 Object post = basicProp.getValue(); 234 235 assertTrue ("After entering text in editor, value should be the text. Expected WOOGLE got " + post, "WOOGLE".equals(post)); 236 237 assertNotSame("After entering data in the custom editor and pressing enter with policy UPDATE_ON_CONFIRMATION, property value should be changed", pre, post); 238 239 basicRen.setUpdatePolicy(PropertyDisplayer.UPDATE_ON_EXPLICIT_REQUEST); 240 241 clickOn(custom.valueField); 242 typeKey(custom.valueField, KeyEvent.VK_N); 243 typeKey(custom.valueField, KeyEvent.VK_I); 244 typeKey(custom.valueField, KeyEvent.VK_F); 245 typeKey(custom.valueField, KeyEvent.VK_T); 246 typeKey(custom.valueField, KeyEvent.VK_Y); 247 248 pre = basicProp.getValue(); 249 250 pressKey(custom.valueField, KeyEvent.VK_ENTER); 251 252 post = basicProp.getValue(); 253 254 assertTrue ("After entering text in editor with policy UPDATE_ON_EXPLICIT_REQUEST, the property value should not be the entered text. Expected NIFTY got " + post, "WOOGLE".equals(post)); 255 256 assertSame("After entering data in the custom editor and pressing enter with policy UPDATE_ON_EXPLICIT_REQUEST, property value should NOT be changed", pre, post); 257 258 259 } 260 261 public void testFailureModes() throws Exception { 262 basicRen.setUpdatePolicy(PropertyDisplayer.UPDATE_ON_CONFIRMATION); 263 BasicCustomEditor custom = (BasicCustomEditor)basicProp.getPropertyEditor().getCustomEditor(); 264 265 custom.setInvalidValueButton.doClick(); 266 sleep(); 267 sleep(); 268 requestFocus(custom.valueField); 269 270 271 IllegalArgumentException iae=null; 272 try { 273 pressKey(custom.valueField, KeyEvent.VK_ENTER); 274 } catch (IllegalArgumentException e) { 275 iae = e; 276 } 277 assertNotNull("Entering a bad value should throw an exception", iae); 278 iae = null; 279 280 custom.setDontAllowValidateButton.doClick(); 281 sleep(); 282 sleep(); 283 requestFocus(custom.valueField); 284 try { 285 pressKey(custom.valueField, KeyEvent.VK_ENTER); 286 } catch (IllegalArgumentException e) { 287 iae = e; 288 } 289 assertNotNull("If a state change on the PropertyEnv causes a PropertyVetoException, an illegal argument exception should be thrown with the message from the PVE", iae); 290 iae = null; 291 292 BasicEditor editor = (BasicEditor) basicRen.getPropertyEditor(); 293 294 295 PropertyEnv env = basicRen.getPropertyEnv(); 296 assertEquals("After a failure to validate, the editor's property env's state should be STATE_INVALID", PropertyEnv.STATE_INVALID, env.getState()); 297 298 assertSame("After a failure to validate, the PropertyEnv the editor is talking to should be the one owned by the CustomEditorDisplayer", env, editor.env); 299 } 300 301 302 public void testValidationMethods() throws Exception { 303 basicRen.setUpdatePolicy(PropertyDisplayer.UPDATE_ON_EXPLICIT_REQUEST); 304 BasicCustomEditor custom = (BasicCustomEditor)basicProp.getPropertyEditor().getCustomEditor(); 305 306 clickOn(custom.valueField); 307 typeKey(custom.valueField, KeyEvent.VK_F); 308 typeKey(custom.valueField, KeyEvent.VK_U); 309 typeKey(custom.valueField, KeyEvent.VK_N); 310 typeKey(custom.valueField, KeyEvent.VK_K); 311 typeKey(custom.valueField, KeyEvent.VK_Y); 312 pressKey(custom.valueField, KeyEvent.VK_ENTER); 313 314 assertTrue("After entering text with update policy UPDATE_ON_EXPLICIT_REQUEST, isValueModified should return true", basicRen.isValueModified()); 315 String legality = basicRen.isModifiedValueLegal(); 316 assertTrue("After entering a legal value with update policy UPDATE_ON_EXPLICIT_REQUEST, isModifiedValueLegal should return null but returned " + legality, legality == null); 317 318 Exception e = null; 319 try { 320 basicRen.commit(); 321 } catch (Exception e1) { 322 e = e1; 323 } 324 assertNull("Committing a legal value should not throw an exception", e); 325 assertEquals("Calling commit() with update policy UPDATE_ON_EXPLICIT_REQUEST should store the edited value in the property", 326 "FUNKY", basicProp.getValue()); 327 328 assertTrue("After committing a legal value, isValueModified should return false", !basicRen.isValueModified()); 329 assertNull("After committing a legal value, isModifiedValueLegal should return null", basicRen.isModifiedValueLegal()); 330 331 custom.setDontAllowValidateButton.doClick(); 332 sleep(); 333 sleep(); 334 335 try { 336 pressKey(custom.valueField, KeyEvent.VK_ENTER); 337 } catch (Exception e2) { 338 339 } 340 341 assertNotNull("With an unvalidatable value, isModifiedValueLegal should return a localized message", basicRen.isModifiedValueLegal()); 342 assertTrue("With an unvalidatable value, isValueModified should return true", basicRen.isValueModified()); 343 344 custom.valueField.setText("foo goo"); 345 custom.setDontAllowValidateButton.doClick(); 346 sleep(); 347 sleep(); 348 349 try { 350 basicRen.commit(); 351 } catch (Exception e3) { 352 e = e3; 353 } 354 355 assertNotNull("Committing an unvalidatable value should throw an exception", e); 356 357 } 358 359 private class FL implements FocusListener { 360 private FocusEvent gainedEvent=null; 361 private FocusEvent lostEvent=null; 362 private int gainedCount=0; 363 private int lostCount=0; 364 public void assertGained() { 365 assertNotNull ("No focus gained received after clicking on an editable renderer", gainedEvent); 366 assertTrue("Received wrong number of focus gained events for a single click on a renderer " + gainedCount, gainedCount == 1); 367 } 368 369 public void assertLost() { 370 assertNotNull ("No focus lost event received after clicking away from a focused, editable renderer", lostEvent); 371 assertTrue("Received wrong number of focus lost events for a single click away from a focused renderer" + lostCount, lostCount == 1); 372 } 373 374 public void focusGained(java.awt.event.FocusEvent e) { 375 gainedEvent = e; 376 gainedCount++; 377 } 378 379 public void focusLost(java.awt.event.FocusEvent e) { 380 lostEvent = e; 381 lostCount++; 382 } 383 } 384 385 private class CL implements ChangeListener { 386 387 private ChangeEvent e; 388 public void assertEvent(String msg) { 389 sleep(); assertNotNull (msg, e); 391 e = null; 392 } 393 394 public void assertNoEvent(String msg) { 395 sleep(); 396 assertNull (e); 397 e = null; 398 } 399 400 public void stateChanged(ChangeEvent e) { 401 this.e = e; 402 } 403 404 } 405 406 private static class TestGCVal extends Object { 407 public String toString() { 408 return "TestGCVal"; 409 } 410 } 411 412 private static class WaitWindow extends WindowAdapter { 413 boolean shown=false; 414 public WaitWindow (JFrame f) { 415 f.addWindowListener(this); 416 f.show(); 417 if (!shown) { 418 synchronized(this) { 419 try { 420 wait(5000); 422 } catch (Exception e) {} 423 } 424 } 425 } 426 427 public void windowOpened(WindowEvent e) { 428 shown = true; 429 synchronized(this) { 430 notifyAll(); 432 ((JFrame ) e.getSource()).removeWindowListener(this); 433 } 434 } 435 } 436 437 private void sleep() { 438 440 try { 441 Thread.currentThread().sleep(SLEEP_LENGTH); 442 } catch (InterruptedException ie) { 443 } 445 446 447 448 450 try { 451 SwingUtilities.invokeAndWait(new Runnable () { 453 public void run() { 454 System.currentTimeMillis(); 455 } 456 }); 457 SwingUtilities.invokeAndWait(new Runnable () { 459 public void run() { 460 System.currentTimeMillis(); 461 } 462 }); 463 } catch (Exception e) { 464 } 465 466 467 } 468 469 private void requestFocus(final JComponent jc) throws Exception { 470 SwingUtilities.invokeAndWait(new Runnable () { 471 public void run() { 472 jc.requestFocus(); 473 } 474 }); 475 sleep(); 476 } 477 478 private void changeProperty (final RendererPropertyDisplayer ren, final Node.Property newProp) throws Exception { 479 SwingUtilities.invokeAndWait(new Runnable () { 480 public void run() { 481 ren.setProperty(newProp); 482 } 483 }); 484 } 485 486 private void clickOn (final JComponent ren, final int fromRight, final int fromTop) throws Exception { 487 SwingUtilities.invokeAndWait (new Runnable () { 488 public void run() { 489 Point toClick = new Point (ren.getWidth() - fromRight, fromTop); 490 Component target=ren.getComponentAt(toClick); 491 toClick = SwingUtilities.convertPoint(ren, toClick, target); 492 System.err.println("Target component is " + target.getClass().getName() + " - " + target + " clicking at " + toClick); 493 494 MouseEvent me = new MouseEvent (target, MouseEvent.MOUSE_PRESSED, System.currentTimeMillis(), MouseEvent.BUTTON1_MASK, toClick.x, toClick.y, 2, false); 495 target.dispatchEvent(me); 496 me = new MouseEvent (target, MouseEvent.MOUSE_RELEASED, System.currentTimeMillis(), MouseEvent.BUTTON1_MASK, toClick.x, toClick.y, 2, false); 497 target.dispatchEvent(me); 498 me = new MouseEvent (target, MouseEvent.MOUSE_CLICKED, System.currentTimeMillis(), MouseEvent.BUTTON1_MASK, toClick.x, toClick.y, 2, false); 499 } 500 }); 501 sleep(); 502 } 503 504 private void clickOn (final JComponent ren) throws Exception { 505 SwingUtilities.invokeAndWait (new Runnable () { 506 public void run() { 507 Point toClick = new Point (5,5); 508 Component target=ren.getComponentAt(toClick); 509 MouseEvent me = new MouseEvent (target, MouseEvent.MOUSE_PRESSED, System.currentTimeMillis(), MouseEvent.BUTTON1_MASK, toClick.x, toClick.y, 2, false); 510 target.dispatchEvent(me); 511 } 512 }); 513 sleep(); 514 } 515 516 private void setEnabled(final CustomEditorDisplayer ren,final boolean val) throws Exception { 517 SwingUtilities.invokeAndWait (new Runnable () { 518 public void run() { 519 ren.setEnabled(val); 520 } 521 }); 522 sleep(); 523 } 524 525 private Exception throwMe = null; 526 private String flushResult = null; 527 private String flushValue(final CustomEditorDisplayer ren) throws Exception { 528 SwingUtilities.invokeAndWait(new Runnable () { 529 public void run() { 530 try { 531 } catch (Exception e) { 533 throwMe = e; 534 flushResult = null; 535 } 536 } 537 }); 538 if (throwMe != null) { 539 try { 540 throw throwMe; 541 } finally { 542 throwMe = null; 543 } 544 } 545 return flushResult; 546 } 547 548 549 private void releaseKey (final Component target, final int key) throws Exception { 550 SwingUtilities.invokeAndWait(new Runnable () { 551 public void run() { 552 KeyEvent ke = new KeyEvent (target, KeyEvent.KEY_RELEASED, System.currentTimeMillis(), 0, key, (char) key); 553 target.dispatchEvent(ke); 554 } 555 }); 556 sleep(); 557 } 558 559 private Exception throwMe2 = null; 560 private void pressKey (final Component target, final int key) throws Exception { 561 SwingUtilities.invokeAndWait(new Runnable () { 562 public void run() { 563 KeyEvent ke = new KeyEvent (target, KeyEvent.KEY_PRESSED, System.currentTimeMillis(), 0, key, (char) key); 564 try { 565 target.dispatchEvent(ke); 566 } catch (Exception e) { 567 throwMe2 = e; 568 } 569 } 570 }); 571 sleep(); 572 if (throwMe2 != null) { 573 Exception e1 = throwMe2; 574 throwMe2 = null; 575 throw e1; 576 } 577 } 578 579 private void shiftPressKey (final Component target, final int key) throws Exception { 580 SwingUtilities.invokeAndWait(new Runnable () { 581 public void run() { 582 KeyEvent ke = new KeyEvent (target, KeyEvent.KEY_PRESSED, System.currentTimeMillis(), KeyEvent.SHIFT_MASK, key, (char) key); 583 target.dispatchEvent(ke); 584 } 585 }); 586 sleep(); 587 } 588 589 590 private void typeKey (final Component target, final int key) throws Exception { 591 SwingUtilities.invokeAndWait(new Runnable () { 592 public void run() { 593 KeyEvent ke = new KeyEvent (target, KeyEvent.KEY_TYPED, System.currentTimeMillis(), 0, KeyEvent.VK_UNDEFINED, (char) key); 594 target.dispatchEvent(ke); 595 } 596 }); 597 sleep(); 598 } 599 600 public class TNode extends AbstractNode { 602 public TNode() { 604 super (Children.LEAF); 605 setName("TNode"); setDisplayName("TNode"); 607 createSheet(); 608 } 609 public Node cloneNode() { 611 return new TNode(); 612 } 613 614 public void addProp (Node.Property p) { 615 props.put(p); 616 this.firePropertyChange(PROP_PROPERTY_SETS, null, null); 617 this.firePropertySetsChange(null, null); 618 } 619 620 Sheet sheet=null; 621 Sheet.Set props=null; 622 protected Sheet createSheet() { 624 sheet = super.createSheet(); 625 props = sheet.get(Sheet.PROPERTIES); 627 if (props == null) { 628 props = Sheet.createPropertiesSet(); 629 sheet.put(props); 630 } 631 props.put(basicProp); 632 props.put(fileProp); 633 634 return sheet; 635 } 636 public void fireMethod(String s, Object o1, Object o2) { 638 firePropertyChange(s,o1,o2); 639 } 640 } 641 642 public class BasicProperty extends PropertySupport { 644 private Object myValue = "Value"; 645 public BasicProperty(String name, boolean isWriteable) { 647 super(name, Object .class, name, "", true, isWriteable); 648 } 649 public Object getValue() { 651 return myValue; 652 } 653 public void setValue(Object value) throws IllegalArgumentException ,IllegalAccessException , InvocationTargetException { 655 System.err.println("BASICPROP setValue to " + value + " (was " + myValue+")"); 656 Object oldVal = myValue; 657 myValue = value; 658 tn.fireMethod(getName(), oldVal, myValue); 659 } 660 public PropertyEditor getPropertyEditor() { 662 return te; 663 } 664 } 665 666 public class FileProperty extends PropertySupport { 668 private Object myValue = new File ("aFile"); 669 public FileProperty(String name, boolean isWriteable) { 671 super(name, File .class, name, "", true, isWriteable); 672 } 673 public Object getValue() { 675 return myValue; 676 } 677 public void setValue(Object value) throws IllegalArgumentException ,IllegalAccessException , InvocationTargetException { 679 Object oldVal = myValue; 680 myValue = value; 681 tn.fireMethod(getName(), oldVal, myValue); 682 } 683 } 684 685 686 public class BasicEditor extends PropertyEditorSupport implements ExPropertyEditor, PropertyChangeListener, VetoableChangeListener { 688 PropertyEnv env; 689 690 public BasicEditor() { 692 } 693 694 698 public void attachEnv(PropertyEnv env) { 699 if (env != null) { 700 env.removeVetoableChangeListener(this); 701 } 702 this.env = env; 703 704 env.setState(env.STATE_VALID); 705 env.addVetoableChangeListener(this); 706 System.err.println(" ATTACHENV"); 707 708 } 709 710 public boolean supportsCustomEditor() { 712 return true; 713 } 714 715 public void setValue(Object newValue) { 717 System.err.println(" BasicEditor.setValue: " + newValue); 718 super.setValue(newValue); 719 } 720 721 public String getAsText() { 722 return getValue() == null ? "null" : getValue().toString(); 723 } 724 725 private Component custom; 726 public Component getCustomEditor() { 727 if (custom == null) { 728 custom = new BasicCustomEditor(this); 729 } 730 return custom; 731 } 732 733 public void vetoNext() { 734 env.setState(env.STATE_NEEDS_VALIDATION); 735 vetoNextChange = true; 736 System.err.println(" veto next"); 737 } 738 739 public void propertyChange(PropertyChangeEvent evt) { 740 741 } 742 743 boolean vetoNextChange=false; 744 public void vetoableChange(PropertyChangeEvent e) throws PropertyVetoException { 745 System.err.println("GOT A VETOABLE CHANGE IN BASIC EDITOR"); 746 PropertyEnv env = (PropertyEnv) e.getSource(); 747 if ((vetoNextChange || "Dont allow validate".equals(getAsText())) && PropertyEnv.STATE_NEEDS_VALIDATION.equals(env.getState())) { 748 System.err.println(" VETOING"); 749 PropertyVetoException pve = new PropertyVetoException ("NoNoNoNoNo", e); 750 ErrorManager.getDefault().annotate(pve, ErrorManager.USER, null, "You can't do that!", null, null); 751 vetoNextChange=false; 752 throw pve; 753 } 754 } 755 756 public void setAsText(String s) { 757 System.err.println(" BasicEditor.setAsText: " + s); 758 if ("invalidValue".equals(s)) { 759 IllegalArgumentException iae = new IllegalArgumentException (); 760 ErrorManager.getDefault().annotate(iae, ErrorManager.USER, "invalid value", "No way", null, null); 761 throw iae; 762 } 763 setValue(s); 764 } 765 766 } 767 768 769 public class BasicCustomEditor extends JPanel implements ActionListener { 770 JTextField valueField=new JTextField (); 771 JButton setInvalidValueButton = new JButton("Invalid value"); 772 JButton setDontAllowValidateButton = new JButton("Dont allow validate"); 773 BasicEditor editor; 774 public BasicCustomEditor(BasicEditor editor) { 775 this.editor = editor; 776 init(); 777 } 778 779 private void init() { 780 setLayout(new FlowLayout ()); 781 valueField.addActionListener(this); 782 setInvalidValueButton.addActionListener(this); 783 setDontAllowValidateButton.addActionListener(this); 784 valueField.setColumns(30); 785 setBackground(Color.ORANGE); 786 add (valueField); 787 add (setInvalidValueButton); 788 add (setDontAllowValidateButton); 789 } 790 boolean processing; 791 public void actionPerformed(ActionEvent e) { 792 processing = true; 793 try { 794 if (e.getSource() == setDontAllowValidateButton) { 795 editor.vetoNext(); 796 valueField.setText("dont allow validate"); 797 } 798 if (e.getSource() == setInvalidValueButton) { 799 valueField.setText("invalidValue"); 800 } 801 if (e.getSource() == valueField) { 802 editor.setAsText(valueField.getText()); 803 } 804 editor.env.setState(PropertyEnv.STATE_NEEDS_VALIDATION); 805 } finally { 806 processing = false; 807 } 808 } 809 810 } 811 } 812 | Popular Tags |