0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.openide.explorer.propertysheet;
0043:
0044: import java.awt.BorderLayout;
0045: import java.awt.BorderLayout;
0046: import java.awt.Color;
0047: import java.awt.Component;
0048: import java.awt.Container;
0049: import java.awt.Dimension;
0050: import java.awt.FlowLayout;
0051: import java.awt.Graphics;
0052: import java.awt.KeyboardFocusManager;
0053: import javax.swing.JFrame;
0054: import java.util.StringTokenizer;
0055: import java.awt.Point;
0056: import java.awt.Rectangle;
0057: import java.awt.Window;
0058: import javax.swing.text.JTextComponent;
0059: import org.openide.explorer.propertysheet.PropertySheet;
0060: import java.awt.event.ActionEvent;
0061: import java.awt.event.ActionListener;
0062: import java.awt.event.FocusEvent;
0063: import java.awt.event.FocusListener;
0064: import java.awt.event.KeyEvent;
0065: import java.awt.event.MouseEvent;
0066: import java.awt.event.WindowAdapter;
0067: import java.awt.event.WindowEvent;
0068: import java.awt.image.BufferedImage;
0069: import org.openide.*;
0070: import org.openide.nodes.*;
0071: import org.openide.explorer.propertysheet.*;
0072: import org.openide.explorer.propertysheet.editors.*;
0073: import java.beans.*;
0074: import java.beans.PropertyVetoException;
0075: import java.io.File;
0076: import java.lang.ref.WeakReference;
0077: import java.lang.reflect.*;
0078: import javax.swing.*;
0079: import javax.swing.ImageIcon;
0080: import javax.swing.JPanel;
0081: import javax.swing.JTextField;
0082: import javax.swing.event.ChangeEvent;
0083: import javax.swing.event.ChangeListener;
0084: import junit.framework.*;
0085: import junit.textui.TestRunner;
0086: import org.netbeans.junit.*;
0087: import org.openide.ErrorManager;
0088: import org.openide.util.Lookup;
0089:
0090: /* A comprehensive test of PropertyPanel */
0091: public class NewPropertyPanelTest extends NbTestCase {
0092:
0093: static {
0094: ComboTest.registerPropertyEditors();
0095: }
0096:
0097: public NewPropertyPanelTest(String name) {
0098: super (name);
0099: }
0100:
0101: public static void main(String args[]) {
0102: // LookAndFeel lf = UIManager.getLookAndFeel();
0103: /* try {
0104: UIManager.setLookAndFeel(new com.jgoodies.plaf.plastic.Plastic3DLookAndFeel());
0105: } catch (Exception e) {
0106: e.printStackTrace();
0107: }
0108: */
0109:
0110: TestRunner.run(suite());
0111:
0112: /*
0113: boolean go=false;
0114: try {
0115: UIManager.setLookAndFeel(new PseudoWindowsLookAndFeel());
0116: go = true;
0117: } catch (NoClassDefFoundError e) {
0118: System.err.println("Couldn't run tests on windows look and feel");
0119: } catch (UnsupportedLookAndFeelException e) {
0120: System.err.println("Couldn't run tests on windows look and feel");
0121: }
0122: if (go) {
0123: TestRunner.run(suite ());
0124: }
0125: go=false;
0126: try {
0127: UIManager.setLookAndFeel(new com.sun.java.swing.plaf.gtk.GTKLookAndFeel());
0128: go = true;
0129: } catch (NoClassDefFoundError e) {
0130: System.err.println("Couldn't run tests on GTK look and feel");
0131: e.printStackTrace();
0132: } catch (UnsupportedLookAndFeelException e) {
0133: System.err.println("Couldn't run tests on GTK look and feel");
0134: e.printStackTrace();
0135: }
0136: if (go) {
0137: TestRunner.run(suite ());
0138: }
0139: try {
0140: UIManager.setLookAndFeel(lf);
0141: } catch (Exception e) {
0142: //highly unlikely
0143: }
0144: */
0145: try {
0146: // new NewPropertyPanelTest("goo").setUp();
0147: } catch (Exception e) {
0148: }
0149:
0150: }
0151:
0152: static int idx = -1;
0153:
0154: public static Test suite() {
0155: return new CustomEditorDisplayerSuite();
0156: }
0157:
0158: private static class CustomEditorDisplayerSuite extends NbTestSuite {
0159: public CustomEditorDisplayerSuite() {
0160: super (NewPropertyPanelTest.class);
0161: }
0162:
0163: public void run(final TestResult tr) {
0164: super .run(tr);
0165: }
0166: }
0167:
0168: /*
0169: * This test creates a Property, Editor and Node. First test checks if initialized
0170: * editor contains the same value as property. The second checks if the property
0171: * value is changed if the same change will be done in the editor.
0172: */
0173:
0174: private JButton focusButton;
0175: PropertyPanel customPanel;
0176: PropertyPanel filePanel;
0177: PropertyPanel tagsPanel;
0178: PropertyPanel stringPanel;
0179:
0180: private TNode tn;
0181: private BasicProperty basicProp;
0182: private FileProperty fileProp;
0183: private BasicEditor te;
0184: private TagsProperty tagsProp;
0185: private StringProperty stringProp;
0186:
0187: private boolean setup = false;
0188: private JFrame jf = null;
0189: private JPanel jp = null;
0190: private int SLEEP_LENGTH = 10; //Make this longer to see what the test is doing
0191:
0192: protected void tearDown() {
0193: if (jf != null) {
0194: // jf.hide();
0195: // jf.dispose();
0196: }
0197: }
0198:
0199: protected void setUp() throws Exception {
0200: PropUtils.forceRadioButtons = false;
0201:
0202: try {
0203: if (setup)
0204: return;
0205: basicProp = new BasicProperty("basicProp", true);
0206: fileProp = new FileProperty("FileProp", true);
0207: tagsProp = new TagsProperty("TagsProp", true);
0208: stringProp = new StringProperty("StringProp", true);
0209:
0210: focusButton = new JButton("Somewhere over the rainbow");
0211: // Create new BasicEditor
0212: te = new BasicEditor();
0213: // Create new TNode
0214: tn = new TNode();
0215:
0216: System.err.println("Crating frame");
0217: jf = new JFrame();
0218: jf.getContentPane().setLayout(new BorderLayout());
0219: jp = new JPanel();
0220: jp.setLayout(new FlowLayout());
0221: jf.getContentPane().add(jp, BorderLayout.CENTER);
0222: jf.setLocation(20, 20);
0223: jf.setSize(600, 600);
0224:
0225: synchronized (jp.getTreeLock()) {
0226: System.err.println("BasicProp = " + basicProp);
0227:
0228: customPanel = new PropertyPanel(basicProp);
0229: filePanel = new PropertyPanel(fileProp);
0230: tagsPanel = new PropertyPanel(tagsProp);
0231: stringPanel = new PropertyPanel(stringProp);
0232:
0233: tagsPanel.setBackground(Color.GREEN);
0234:
0235: filePanel.setBackground(Color.YELLOW);
0236:
0237: stringPanel.setBackground(Color.PINK);
0238:
0239: customPanel
0240: .setPreferences(PropertyPanel.PREF_CUSTOM_EDITOR);
0241:
0242: filePanel
0243: .setPreferences(PropertyPanel.PREF_CUSTOM_EDITOR);
0244:
0245: jp.add(customPanel);
0246:
0247: jp.add(filePanel);
0248:
0249: jp.add(focusButton);
0250:
0251: jp.add(stringPanel);
0252:
0253: jp.add(tagsPanel);
0254: }
0255:
0256: System.err.println("Waiting for window");
0257: new WaitWindow(jf); //block until window open
0258: System.err.println("Window shown");
0259: } catch (Exception e) {
0260: e.printStackTrace();
0261: } finally {
0262: setup = true;
0263: }
0264: }
0265:
0266: public void testReadOnlyMode() throws Exception {
0267: requestFocus(focusButton);
0268: changeProperty(stringPanel, stringProp);
0269: setPreferences(stringPanel, PropertyPanel.PREF_READ_ONLY
0270: | PropertyPanel.PREF_INPUT_STATE);
0271: Component owner = KeyboardFocusManager
0272: .getCurrentKeyboardFocusManager().getFocusOwner();
0273:
0274: requestFocus(stringPanel);
0275: Component owner2 = KeyboardFocusManager
0276: .getCurrentKeyboardFocusManager().getFocusOwner();
0277:
0278: assertSame(
0279: "Requesting focus on a read only inline editor panel should not change the focus owner, but it was "
0280: + owner2, owner, owner2);
0281:
0282: requestFocus(stringPanel);
0283: setPreferences(filePanel, PropertyPanel.PREF_READ_ONLY
0284: | PropertyPanel.PREF_CUSTOM_EDITOR);
0285: jf.repaint();
0286: Component owner3 = KeyboardFocusManager
0287: .getCurrentKeyboardFocusManager().getFocusOwner();
0288:
0289: assertSame(
0290: "Requesting focus on a read only custom editor panel should not change the focus owner, not "
0291: + owner3, owner, owner3);
0292: }
0293:
0294: public void testEnabled() throws Exception {
0295: requestFocus(focusButton);
0296: sleep();
0297: changeProperty(filePanel, fileProp);
0298: sleep();
0299: setEnabled(filePanel, false);
0300: sleep();
0301: Component owner = KeyboardFocusManager
0302: .getCurrentKeyboardFocusManager().getFocusOwner();
0303:
0304: requestFocus(filePanel);
0305: Component owner2 = KeyboardFocusManager
0306: .getCurrentKeyboardFocusManager().getFocusOwner();
0307:
0308: assertSame(
0309: "Requesting focus on a disabled inline editor panel should not change the focus owner, but it was "
0310: + owner2, owner, owner2);
0311:
0312: setPreferences(filePanel, PropertyPanel.PREF_CUSTOM_EDITOR);
0313:
0314: requestFocus(filePanel);
0315: Component owner3 = KeyboardFocusManager
0316: .getCurrentKeyboardFocusManager().getFocusOwner();
0317:
0318: assertSame(
0319: "Requesting focus on a disabled custom editor panel should not change the focus owner, not "
0320: + owner3, owner, owner3);
0321:
0322: setPreferences(filePanel, PropertyPanel.PREF_INPUT_STATE);
0323:
0324: Component owner4 = KeyboardFocusManager
0325: .getCurrentKeyboardFocusManager().getFocusOwner();
0326:
0327: assertSame(
0328: "Changing preferences on a property panel should not enable it to be focused if it is disabled"
0329: + owner4, owner, owner4);
0330:
0331: setEnabled(filePanel, true);
0332:
0333: requestFocus(filePanel);
0334:
0335: Component owner5 = KeyboardFocusManager
0336: .getCurrentKeyboardFocusManager().getFocusOwner();
0337: assertNotSame(
0338: "Setting enabled to true should restore focusability",
0339: owner5, owner);
0340: assertTrue(
0341: "Setting enabled to true and requesting focus should set focus to a child of the panel",
0342: filePanel.isAncestorOf(owner5));
0343:
0344: requestFocus(focusButton);
0345: owner5 = KeyboardFocusManager.getCurrentKeyboardFocusManager()
0346: .getFocusOwner();
0347: //XXX better to do this for JFileChooser, but it has bugs - it *is* still focusable
0348:
0349: changeProperty(filePanel, stringProp);
0350: setEnabled(filePanel, false);
0351: requestFocus(focusButton);
0352: owner5 = KeyboardFocusManager.getCurrentKeyboardFocusManager()
0353: .getFocusOwner();
0354:
0355: setPreferences(filePanel, PropertyPanel.PREF_CUSTOM_EDITOR);
0356: requestFocus(focusButton);
0357: jp.repaint();
0358: sleep();
0359:
0360: requestFocus(filePanel);
0361: Component owner6 = KeyboardFocusManager
0362: .getCurrentKeyboardFocusManager().getFocusOwner();
0363:
0364: assertTrue(
0365: "Setting focus on a disabled custom editor component should neither set focus to it nor its children, but focus is on "
0366: + owner6, owner6 != filePanel
0367: && !filePanel.isAncestorOf(owner6));
0368: }
0369:
0370: public void testChangingPreferences() throws Exception {
0371: Dimension d = filePanel.getPreferredSize();
0372: requestFocus(filePanel);
0373: sleep();
0374: Component owner = KeyboardFocusManager
0375: .getCurrentKeyboardFocusManager().getFocusOwner();
0376:
0377: assertTrue(
0378: "After requesting focus on an enabled property panel containing a file custom editor, focus should be on some child of the property panel, but it is "
0379: + owner, filePanel.isAncestorOf(owner));
0380:
0381: sleep();
0382:
0383: setPreferences(filePanel, PropertyPanel.PREF_INPUT_STATE);
0384: jf.validate();
0385: jf.repaint();
0386: Dimension d2 = filePanel.getPreferredSize();
0387: assertTrue(
0388: "Panel returned same preferred size in inline and custom editor mode. Probably the inner component wasn't changed when the preferences were changed.",
0389: !d.equals(d2));
0390: sleep();
0391:
0392: Component newOwner = KeyboardFocusManager
0393: .getCurrentKeyboardFocusManager().getFocusOwner();
0394: assertTrue(
0395: "After changing preferences from custom editor to non-custom editor in a displayed property panel, focus owner should still be in panel, but it is "
0396: + newOwner, filePanel.isAncestorOf(newOwner));
0397: }
0398:
0399: public void testPropertyPanelSendsFocusLost() throws Exception {
0400: //This test is in referenced to a filed issue that the old property
0401: //panel did not send focus lost events properly
0402:
0403: requestFocus(focusButton);
0404: FL fliFile = new FL();
0405: FL fliBasic = new FL();
0406: filePanel.addFocusListener(fliFile);
0407: customPanel.addFocusListener(fliBasic);
0408:
0409: requestFocus(filePanel);
0410: fliFile
0411: .assertGained("Setting focus to a custom editor did not generate a focus gained event");
0412:
0413: requestFocus(customPanel);
0414: fliFile
0415: .assertLost("Setting focus from one custom editor to another did not generate a focus lost event from the first one");
0416:
0417: fliBasic
0418: .assertGained("Setting focus to a custom editor from another did not generate a focus gained event from the second one");
0419:
0420: requestFocus(focusButton);
0421: fliBasic
0422: .assertLost("Setting focus to a non property panel component did not generate a focus lost event");
0423:
0424: setPreferences(filePanel, PropertyPanel.PREF_INPUT_STATE);
0425:
0426: requestFocus(filePanel);
0427: fliFile
0428: .assertGained("Setting focus to a property panel displaying an inline editor from a non-property panel component did not generate a focus gained event");
0429:
0430: requestFocus(focusButton);
0431: fliFile
0432: .assertLost("Setting focus away from a property panel displaying an inline editor to a non-property panel component did not generate a focus lost event");
0433: }
0434:
0435: public void testTableUIBehavior() throws Exception {
0436: requestFocus(tagsPanel);
0437:
0438: System.err.println("TAGS PANEL BOUNDS: "
0439: + tagsPanel.getBounds());
0440:
0441: Component focusOwner = KeyboardFocusManager
0442: .getCurrentKeyboardFocusManager()
0443: .getPermanentFocusOwner();
0444: assertTrue(
0445: "After requesting focus on a property with tags, a combo box should have focus, not "
0446: + focusOwner, focusOwner instanceof JComboBox);
0447:
0448: assertTrue(
0449: "After requesting focus on a property with tags, with TableUI false, the combo's popup should not be open",
0450: !((JComboBox) focusOwner).isPopupVisible());
0451:
0452: requestFocus(focusButton);
0453:
0454: tagsPanel.setPreferences(PropertyPanel.PREF_TABLEUI);
0455:
0456: requestFocus(tagsPanel);
0457: focusOwner = KeyboardFocusManager
0458: .getCurrentKeyboardFocusManager()
0459: .getPermanentFocusOwner();
0460:
0461: assertTrue(
0462: "After requesting focus on a property with tags, a combo box should have focus, not "
0463: + focusOwner, focusOwner instanceof JComboBox);
0464:
0465: assertTrue(
0466: "After requesting focus on a property with tags, with TableUI true, the combo's popup should be open",
0467: ((JComboBox) focusOwner).isPopupVisible());
0468:
0469: sleep();
0470: requestFocus(focusButton);
0471:
0472: /*
0473: //Commenting this out for now - too heavily depends to on the look and
0474: //feel's behavior
0475: assertTrue("After shifting focus away from a tableUI combo box, its popup should no longer be open",
0476: !((JComboBox) focusOwner).isPopupVisible());
0477: */
0478:
0479: }
0480:
0481: public void testClientProperties() throws Exception {
0482: tagsPanel.putClientProperty("radioButtonMax", new Integer(100));
0483: sleep();
0484: sleep();
0485: requestFocus(tagsPanel);
0486: Component focusOwner = KeyboardFocusManager
0487: .getCurrentKeyboardFocusManager()
0488: .getPermanentFocusOwner();
0489:
0490: assertTrue(
0491: "After setting focus to a panel for a property editor with tags below the radio button threshold, focus should be on a radio button, but was "
0492: + focusOwner,
0493: focusOwner instanceof JRadioButton);
0494:
0495: requestFocus(focusButton);
0496:
0497: tagsPanel.putClientProperty("radioButtonMax", null);
0498: sleep();
0499: sleep();
0500: requestFocus(tagsPanel);
0501: Component focusOwner2 = KeyboardFocusManager
0502: .getCurrentKeyboardFocusManager()
0503: .getPermanentFocusOwner();
0504:
0505: assertNotSame(
0506: "Focus owner should not be same as previous if the value of radioButtonMax has changed significantly",
0507: focusOwner, focusOwner2);
0508:
0509: assertTrue(
0510: "After resetting radioButtonMax client property and requesting focus, a radio button should not be what gets focus on requestFocus",
0511: (!(focusOwner2 instanceof JRadioButton)));
0512:
0513: assertTrue(
0514: "After resetting radioButtonMax client property and requesting focus, a combo box should be what gets focus on requestFocus",
0515: focusOwner2 instanceof JComboBox);
0516:
0517: requestFocus(focusButton);
0518:
0519: tagsPanel.putClientProperty("radioButtonMax", new Integer(100));
0520: sleep();
0521: tagsPanel.putClientProperty("useLabels", Boolean.TRUE);
0522:
0523: sleep();
0524:
0525: }
0526:
0527: public void testReplaceProperty() throws Exception {
0528: Node.Property p = stringPanel.getProperty();
0529: requestFocus(stringPanel);
0530: typeKey(stringPanel, KeyEvent.VK_W);
0531: typeKey(stringPanel, KeyEvent.VK_H);
0532: typeKey(stringPanel, KeyEvent.VK_O);
0533: typeKey(stringPanel, KeyEvent.VK_A);
0534:
0535: changeProperty(stringPanel, tagsProp);
0536:
0537: Node.Property p2 = stringPanel.getProperty();
0538:
0539: assertNotSame(
0540: "After replacing the property, it should not be the former one",
0541: p2, p);
0542:
0543: setPreferences(stringPanel, PropertyPanel.PREF_CUSTOM_EDITOR);
0544:
0545: changeProperty(stringPanel, fileProp);
0546:
0547: PCL pcl = new PCL();
0548: stringPanel.addPropertyChangeListener(pcl);
0549:
0550: //Set the value in a way that will trigger an env property change
0551: //on a property the panel should no longer be listening to
0552: tagsProp.getPropertyEditor().setAsText("c"); //will be an invalid value
0553:
0554: pcl
0555: .assertNoEvent("Change in a property editor not related to the current property in a propertypanel whose property was changed nonetheless triggered a state changed event from the panel");
0556:
0557: filePanel.setPreferences(PropertyPanel.PREF_CUSTOM_EDITOR);
0558: requestFocus(filePanel);
0559: Component focusOwner = KeyboardFocusManager
0560: .getCurrentKeyboardFocusManager()
0561: .getPermanentFocusOwner();
0562:
0563: changeProperty(filePanel, stringProp);
0564: requestFocus(filePanel);
0565:
0566: Component focusOwner2 = KeyboardFocusManager
0567: .getCurrentKeyboardFocusManager()
0568: .getPermanentFocusOwner();
0569:
0570: assertNotSame(
0571: "After changing the property in a custom editor panel to one with different property type, the component focus gets set to on a call to requestFocus should not be the same type as before",
0572: focusOwner.getClass(), focusOwner2.getClass());
0573: }
0574:
0575: public void testWriteValues() throws Exception {
0576: stringPanel.setChangeImmediate(false);
0577: assertTrue("Panel contains the wrong property: "
0578: + stringPanel.getProperty(),
0579: stringPanel.getProperty() == stringProp);
0580:
0581: requestFocus(stringPanel);
0582: Component focusOwner = KeyboardFocusManager
0583: .getCurrentKeyboardFocusManager()
0584: .getPermanentFocusOwner();
0585: assertTrue(
0586: "Requesting focus on a property panel for a string property should set focus to a JTextField not "
0587: + focusOwner,
0588: focusOwner instanceof JTextComponent);
0589:
0590: typeKey(stringPanel, KeyEvent.VK_T);
0591: typeKey(stringPanel, KeyEvent.VK_H);
0592: typeKey(stringPanel, KeyEvent.VK_E);
0593: typeKey(stringPanel, KeyEvent.VK_R);
0594: typeKey(stringPanel, KeyEvent.VK_E);
0595: typeKey(stringPanel, KeyEvent.VK_S);
0596: typeKey(stringPanel, KeyEvent.VK_SPACE);
0597: typeKey(stringPanel, KeyEvent.VK_A);
0598:
0599: Object o = stringPanel.getProperty().getValue();
0600: assertTrue(
0601: "After typing into a property panel string editor, property value should not be what was typed",
0602: !o.equals("THERES A"));
0603:
0604: //pressKey(focusOwner, KeyEvent.VK_ENTER);
0605: stringPanel.updateValue();
0606: Object o2 = stringPanel.getProperty().getValue();
0607:
0608: assertNotSame(o, o2);
0609: assertTrue(
0610: "After typing into a property panel string editor and pressing enter, property value should be what was typed, but it was <"
0611: + o + ">", o2.equals("THERES A"));
0612: }
0613:
0614: public void testMarkingUpdates() throws Exception {
0615: requestFocus(tagsPanel);
0616: sleep();
0617:
0618: InplaceEditor outer = ((EditablePropertyDisplayer) tagsPanel.inner)
0619: .getInplaceEditor();
0620: assertTrue(
0621: "Should be a button panel for component supporting a custom editor",
0622: outer instanceof ButtonPanel);
0623: assertTrue(
0624: "Button panel should contain a combo box",
0625: ((ButtonPanel) outer).getInplaceEditor() instanceof ComboInplaceEditor);
0626:
0627: sleep();
0628: sleep();
0629: pressKey(tagsPanel, KeyEvent.VK_DOWN);
0630: pressKey(tagsPanel, KeyEvent.VK_UP);
0631: pressKey(tagsPanel, KeyEvent.VK_UP);
0632:
0633: InplaceEditor newOuter = ((EditablePropertyDisplayer) tagsPanel.inner)
0634: .getInplaceEditor();
0635: // assertTrue ("After setting an illegal value, the outer component should be an IconPanel to show the illegal value mark, not " + newOuter,
0636: // newOuter instanceof IconPanel);
0637:
0638: pressKey(tagsPanel, KeyEvent.VK_UP);
0639:
0640: sleep();
0641: sleep();
0642: newOuter = ((EditablePropertyDisplayer) tagsPanel.inner)
0643: .getInplaceEditor();
0644: sleep();
0645: assertTrue(
0646: "After setting a legal value, the outer component should be an IconPanel to show the illegal value mark, but it is "
0647: + newOuter, newOuter instanceof ButtonPanel);
0648: }
0649:
0650: public void testSuppressEditorButton() throws Exception {
0651: requestFocus(tagsPanel);
0652: InplaceEditor outer = ((EditablePropertyDisplayer) tagsPanel.inner)
0653: .getInplaceEditor();
0654: assertTrue(
0655: "Should be a button panel for component supporting a custom editor",
0656: outer instanceof ButtonPanel);
0657:
0658: tagsPanel.putClientProperty("suppressCustomEditor",
0659: Boolean.TRUE);
0660: sleep();
0661: sleep();
0662: sleep();
0663:
0664: outer = ((EditablePropertyDisplayer) tagsPanel.inner)
0665: .getInplaceEditor();
0666:
0667: assertTrue(
0668: "Should be no button panel when suppressing custom editor",
0669: !(outer instanceof ButtonPanel));
0670: }
0671:
0672: private class PCL implements PropertyChangeListener {
0673: private PropertyChangeEvent event;
0674:
0675: public void assertNoEvent(String msg) {
0676: assertNull(msg, event);
0677: }
0678:
0679: public void assertEvent(String msg) {
0680: PropertyChangeEvent pce = event;
0681: event = null;
0682: assertNotNull(msg, event);
0683: }
0684:
0685: public void propertyChange(PropertyChangeEvent evt) {
0686:
0687: }
0688:
0689: }
0690:
0691: private void setPreferences(final PropertyPanel pp,
0692: final int preferences) throws Exception {
0693: SwingUtilities.invokeAndWait(new Runnable() {
0694: public void run() {
0695: throwMe = null;
0696: try {
0697: pp.setPreferences(preferences);
0698: } catch (Exception e) {
0699: throwMe = e;
0700: }
0701: }
0702: });
0703: if (throwMe != null) {
0704: Exception e = throwMe;
0705: throwMe = null;
0706: throw e;
0707: } else {
0708: sleep();
0709: }
0710: }
0711:
0712: private class FL implements FocusListener {
0713: private FocusEvent gainedEvent = null;
0714: private FocusEvent lostEvent = null;
0715: private int gainedCount = 0;
0716: private int lostCount = 0;
0717:
0718: public void assertGained(String msg) {
0719: int currGainedCount = gainedCount;
0720: gainedCount = 0;
0721: FocusEvent gained = gainedEvent;
0722: gainedEvent = null;
0723: assertNotNull(msg, gained);
0724: assertTrue(
0725: "Received wrong number of focus gained events for a single click on a renderer "
0726: + currGainedCount, currGainedCount == 1);
0727: }
0728:
0729: public void assertLost(String msg) {
0730: int currLostCount = lostCount;
0731: lostCount = 0;
0732: FocusEvent lost = lostEvent;
0733: lostEvent = null;
0734: assertNotNull(msg, lost);
0735: assertTrue(
0736: "Received wrong number of focus lost events for a single click away from a focused renderer"
0737: + currLostCount, currLostCount == 1);
0738: }
0739:
0740: public void focusGained(java.awt.event.FocusEvent e) {
0741: gainedEvent = e;
0742: gainedCount++;
0743: }
0744:
0745: public void focusLost(java.awt.event.FocusEvent e) {
0746: lostEvent = e;
0747: lostCount++;
0748: }
0749: }
0750:
0751: private class CL implements ChangeListener {
0752:
0753: private ChangeEvent e;
0754:
0755: public void assertEvent(String msg) {
0756: sleep(); //give the event time to happen
0757: assertNotNull(msg, e);
0758: e = null;
0759: }
0760:
0761: public void assertNoEvent(String msg) {
0762: sleep();
0763: assertNull(e);
0764: e = null;
0765: }
0766:
0767: public void stateChanged(ChangeEvent e) {
0768: this .e = e;
0769: }
0770:
0771: }
0772:
0773: private static class TestGCVal extends Object {
0774: public String toString() {
0775: return "TestGCVal";
0776: }
0777: }
0778:
0779: private static class WaitWindow extends WindowAdapter {
0780: boolean shown = false;
0781:
0782: public WaitWindow(JFrame f) {
0783: f.addWindowListener(this );
0784: f.show();
0785: f.toFront();
0786: f.requestFocus();
0787: if (!shown) {
0788: synchronized (this ) {
0789: try {
0790: //System.err.println("Waiting for window");
0791: wait(6000);
0792: } catch (Exception e) {
0793: }
0794: }
0795: }
0796: int ct = 0;
0797: while (!f.isShowing()) {
0798: ct++;
0799: try {
0800: Thread.currentThread().sleep(400);
0801: } catch (Exception e) {
0802:
0803: }
0804: if (ct > 100) {
0805: break;
0806: }
0807: }
0808: ct = 0;
0809: Container c = KeyboardFocusManager
0810: .getCurrentKeyboardFocusManager().getActiveWindow();
0811: while (c != f) {
0812: try {
0813: Thread.currentThread().sleep(400);
0814: } catch (Exception e) {
0815:
0816: }
0817: c = KeyboardFocusManager
0818: .getCurrentKeyboardFocusManager()
0819: .getActiveWindow();
0820: ct++;
0821: if (ct > 100) {
0822: break;
0823: }
0824: }
0825: }
0826:
0827: public void windowOpened(WindowEvent e) {
0828: shown = true;
0829: synchronized (this ) {
0830: //System.err.println("window opened");
0831: notifyAll();
0832: ((JFrame) e.getSource()).removeWindowListener(this );
0833: }
0834: }
0835: }
0836:
0837: private void sleep() {
0838: //useful when running interactively
0839:
0840: try {
0841: Thread.currentThread().sleep(SLEEP_LENGTH);
0842: } catch (InterruptedException ie) {
0843: //go away
0844: }
0845:
0846: //runs faster -uncomment for production use
0847:
0848: try {
0849: //jf.getTreeLock().wait();
0850: SwingUtilities.invokeAndWait(new Runnable() {
0851: public void run() {
0852: System.currentTimeMillis();
0853: }
0854: });
0855: //jf.getTreeLock().wait();
0856: SwingUtilities.invokeAndWait(new Runnable() {
0857: public void run() {
0858: System.currentTimeMillis();
0859: }
0860: });
0861: } catch (Exception e) {
0862: }
0863:
0864: }
0865:
0866: private void requestFocus(final JComponent jc) throws Exception {
0867: SwingUtilities.invokeAndWait(new Runnable() {
0868: public void run() {
0869: jc.requestFocus();
0870: }
0871: });
0872: sleep();
0873: }
0874:
0875: private void changeProperty(final PropertyPanel ren,
0876: final Node.Property newProp) throws Exception {
0877: SwingUtilities.invokeAndWait(new Runnable() {
0878: public void run() {
0879: ren.setProperty(newProp);
0880: }
0881: });
0882: }
0883:
0884: private void clickOn(final JComponent ren, final int fromRight,
0885: final int fromTop) throws Exception {
0886: SwingUtilities.invokeAndWait(new Runnable() {
0887: public void run() {
0888: Point toClick = new Point(ren.getWidth() - fromRight,
0889: fromTop);
0890: Component target = ren.getComponentAt(toClick);
0891: toClick = SwingUtilities.convertPoint(ren, toClick,
0892: target);
0893: System.err.println("Target component is "
0894: + target.getClass().getName() + " - " + target
0895: + " clicking at " + toClick);
0896:
0897: MouseEvent me = new MouseEvent(target,
0898: MouseEvent.MOUSE_PRESSED, System
0899: .currentTimeMillis(),
0900: MouseEvent.BUTTON1_MASK, toClick.x, toClick.y,
0901: 2, false);
0902: target.dispatchEvent(me);
0903: me = new MouseEvent(target, MouseEvent.MOUSE_RELEASED,
0904: System.currentTimeMillis(),
0905: MouseEvent.BUTTON1_MASK, toClick.x, toClick.y,
0906: 2, false);
0907: target.dispatchEvent(me);
0908: me = new MouseEvent(target, MouseEvent.MOUSE_CLICKED,
0909: System.currentTimeMillis(),
0910: MouseEvent.BUTTON1_MASK, toClick.x, toClick.y,
0911: 2, false);
0912: }
0913: });
0914: sleep();
0915: }
0916:
0917: private void clickOn(final JComponent ren) throws Exception {
0918: SwingUtilities.invokeAndWait(new Runnable() {
0919: public void run() {
0920: Point toClick = new Point(5, 5);
0921: Component target = ren.getComponentAt(toClick);
0922: MouseEvent me = new MouseEvent(target,
0923: MouseEvent.MOUSE_PRESSED, System
0924: .currentTimeMillis(),
0925: MouseEvent.BUTTON1_MASK, toClick.x, toClick.y,
0926: 2, false);
0927: target.dispatchEvent(me);
0928: }
0929: });
0930: sleep();
0931: }
0932:
0933: private void setEnabled(final PropertyPanel ren, final boolean val)
0934: throws Exception {
0935: SwingUtilities.invokeAndWait(new Runnable() {
0936: public void run() {
0937: ren.setEnabled(val);
0938: }
0939: });
0940: sleep();
0941: }
0942:
0943: private Exception throwMe = null;
0944: private String flushResult = null;
0945:
0946: private String flushValue(final PropertyPanel ren) throws Exception {
0947: SwingUtilities.invokeAndWait(new Runnable() {
0948: public void run() {
0949: try {
0950: //flushResult = ren.flushValue();
0951: } catch (Exception e) {
0952: throwMe = e;
0953: flushResult = null;
0954: }
0955: }
0956: });
0957: if (throwMe != null) {
0958: try {
0959: throw throwMe;
0960: } finally {
0961: throwMe = null;
0962: }
0963: }
0964: return flushResult;
0965: }
0966:
0967: private void releaseKey(final Component target, final int key)
0968: throws Exception {
0969: SwingUtilities.invokeAndWait(new Runnable() {
0970: public void run() {
0971: KeyEvent ke = new KeyEvent(target,
0972: KeyEvent.KEY_RELEASED, System
0973: .currentTimeMillis(), 0, key,
0974: (char) key);
0975: target.dispatchEvent(ke);
0976: }
0977: });
0978: sleep();
0979: }
0980:
0981: private Exception throwMe2 = null;
0982:
0983: private void pressKey(final Component target, final int key)
0984: throws Exception {
0985: SwingUtilities.invokeAndWait(new Runnable() {
0986: public void run() {
0987: KeyEvent ke = new KeyEvent(target,
0988: KeyEvent.KEY_PRESSED, System
0989: .currentTimeMillis(), 0, key,
0990: (char) key);
0991: try {
0992: target.dispatchEvent(ke);
0993: } catch (Exception e) {
0994: throwMe2 = e;
0995: }
0996: }
0997: });
0998: sleep();
0999: if (throwMe2 != null) {
1000: Exception e1 = throwMe2;
1001: throwMe2 = null;
1002: throw e1;
1003: }
1004: }
1005:
1006: private void shiftPressKey(final Component target, final int key)
1007: throws Exception {
1008: SwingUtilities.invokeAndWait(new Runnable() {
1009: public void run() {
1010: KeyEvent ke = new KeyEvent(target,
1011: KeyEvent.KEY_PRESSED, System
1012: .currentTimeMillis(),
1013: KeyEvent.SHIFT_MASK, key, (char) key);
1014: target.dispatchEvent(ke);
1015: }
1016: });
1017: sleep();
1018: }
1019:
1020: private void typeKey(final Component target, final int key)
1021: throws Exception {
1022: SwingUtilities.invokeAndWait(new Runnable() {
1023: public void run() {
1024: KeyEvent ke = new KeyEvent(target, KeyEvent.KEY_TYPED,
1025: System.currentTimeMillis(), 0,
1026: KeyEvent.VK_UNDEFINED, (char) key);
1027: target.dispatchEvent(ke);
1028: }
1029: });
1030: sleep();
1031: }
1032:
1033: //Node definition
1034: public class TNode extends AbstractNode {
1035: //create Node
1036: public TNode() {
1037: super (Children.LEAF);
1038: setName("TNode"); // or, super.setName if needed
1039: setDisplayName("TNode");
1040: createSheet();
1041: }
1042:
1043: //clone existing Node
1044: public Node cloneNode() {
1045: return new TNode();
1046: }
1047:
1048: public void addProp(Node.Property p) {
1049: props.put(p);
1050: this .firePropertyChange(PROP_PROPERTY_SETS, null, null);
1051: this .firePropertySetsChange(null, null);
1052: }
1053:
1054: Sheet sheet = null;
1055: Sheet.Set props = null;
1056:
1057: // Create a property sheet:
1058: protected Sheet createSheet() {
1059: sheet = super .createSheet();
1060: // Make sure there is a "Properties" set:
1061: props = sheet.get(Sheet.PROPERTIES);
1062: if (props == null) {
1063: props = Sheet.createPropertiesSet();
1064: sheet.put(props);
1065: }
1066: props.put(basicProp);
1067: props.put(fileProp);
1068:
1069: return sheet;
1070: }
1071:
1072: // Method firing changes
1073: public void fireMethod(String s, Object o1, Object o2) {
1074: firePropertyChange(s, o1, o2);
1075: }
1076: }
1077:
1078: // Property definition
1079: public class BasicProperty extends PropertySupport {
1080: private Object myValue = "Value";
1081:
1082: // Create new Property
1083: public BasicProperty(String name, boolean isWriteable) {
1084: super (name, Object.class, name, "", true, isWriteable);
1085: }
1086:
1087: // get property value
1088: public Object getValue() {
1089: return myValue;
1090: }
1091:
1092: // set property value
1093: public void setValue(Object value)
1094: throws IllegalArgumentException,
1095: IllegalAccessException, InvocationTargetException {
1096: System.err.println("BASICPROP setValue to " + value
1097: + " (was " + myValue + ")");
1098: Object oldVal = myValue;
1099: myValue = value;
1100: tn.fireMethod(getName(), oldVal, myValue);
1101: }
1102:
1103: // get the property editor
1104: public PropertyEditor getPropertyEditor() {
1105: return te;
1106: }
1107: }
1108:
1109: // Property definition
1110: public class FileProperty extends PropertySupport {
1111: private Object myValue = new File("aFile");
1112:
1113: // Create new Property
1114: public FileProperty(String name, boolean isWriteable) {
1115: super (name, File.class, name, "", true, isWriteable);
1116: }
1117:
1118: // get property value
1119: public Object getValue() {
1120: return myValue;
1121: }
1122:
1123: // set property value
1124: public void setValue(Object value)
1125: throws IllegalArgumentException,
1126: IllegalAccessException, InvocationTargetException {
1127: Object oldVal = myValue;
1128: myValue = value;
1129: tn.fireMethod(getName(), oldVal, myValue);
1130: }
1131: }
1132:
1133: // Property definition
1134: public class TagsProperty extends PropertySupport {
1135: private Object myValue = "Value";
1136:
1137: // Create new Property
1138: public TagsProperty(String name, boolean isWriteable) {
1139: super (name, Object.class, name, "", true, isWriteable);
1140: }
1141:
1142: // get property value
1143: public Object getValue() {
1144: return myValue;
1145: }
1146:
1147: // set property value
1148: public void setValue(Object value)
1149: throws IllegalArgumentException,
1150: IllegalAccessException, InvocationTargetException {
1151: Object oldVal = myValue;
1152: myValue = value;
1153: tn.fireMethod(getName(), oldVal, myValue);
1154: }
1155:
1156: // get the property editor
1157: PropertyEditor editor = null;
1158:
1159: public PropertyEditor getPropertyEditor() {
1160: if (editor == null) {
1161: editor = new TagsEditor();
1162: }
1163: return editor;
1164: }
1165: }
1166:
1167: // Property definition
1168: public class StringProperty extends PropertySupport {
1169: private Object myValue = "way up high";
1170:
1171: // Create new Property
1172: public StringProperty(String name, boolean isWriteable) {
1173: super (name, String.class, name, "", true, isWriteable);
1174: }
1175:
1176: // get property value
1177: public Object getValue() {
1178: return myValue;
1179: }
1180:
1181: // set property value
1182: public void setValue(Object value)
1183: throws IllegalArgumentException,
1184: IllegalAccessException, InvocationTargetException {
1185: System.err.println("SETVALUE ON STRINGPROPERTY: " + value);
1186: Object oldVal = myValue;
1187: myValue = value;
1188: tn.fireMethod(getName(), oldVal, myValue);
1189: }
1190: }
1191:
1192: public class TagsEditor extends PropertyEditorSupport implements
1193: ExPropertyEditor {
1194: PropertyEnv env;
1195:
1196: public TagsEditor() {
1197: }
1198:
1199: public String[] getTags() {
1200: return new String[] { "a", "b", "c", "d", "Value" };
1201: }
1202:
1203: public void attachEnv(PropertyEnv env) {
1204: this .env = env;
1205: if ("c".equals(getValue())) {
1206: env.setState(env.STATE_INVALID);
1207: } else {
1208: env.setState(env.STATE_VALID);
1209: }
1210: }
1211:
1212: public boolean supportsCustomEditor() {
1213: return true;
1214: }
1215:
1216: public Component getCustomEditor() {
1217: return new JColorChooser();
1218: }
1219:
1220: public void setValue(Object newValue) {
1221: super .setValue(newValue);
1222: if (env != null) {
1223: if ("c".equals(newValue)) {
1224: env.setState(env.STATE_INVALID);
1225: } else {
1226: env.setState(env.STATE_NEEDS_VALIDATION);
1227: }
1228: }
1229: }
1230: }
1231:
1232: // Editor definition
1233: public class BasicEditor extends PropertyEditorSupport implements
1234: ExPropertyEditor, PropertyChangeListener,
1235: VetoableChangeListener {
1236: PropertyEnv env;
1237:
1238: // Create new BasicEditor
1239: public BasicEditor() {
1240: }
1241:
1242: /*
1243: * This method is called by the IDE to pass
1244: * the environment to the property editor.
1245: */
1246: public void attachEnv(PropertyEnv env) {
1247: if (env != null) {
1248: env.removeVetoableChangeListener(this );
1249: }
1250: this .env = env;
1251:
1252: env.setState(env.STATE_VALID);
1253: env.addVetoableChangeListener(this );
1254: System.err.println(" ATTACHENV");
1255:
1256: }
1257:
1258: // Set that this Editor doesn't support custom Editor
1259: public boolean supportsCustomEditor() {
1260: return true;
1261: }
1262:
1263: // Set the Property value threw the Editor
1264: public void setValue(Object newValue) {
1265: System.err.println(" BasicEditor.setValue: " + newValue);
1266: super .setValue(newValue);
1267: }
1268:
1269: public String getAsText() {
1270: return getValue() == null ? "null" : getValue().toString();
1271: }
1272:
1273: private Component custom;
1274:
1275: public Component getCustomEditor() {
1276: if (custom == null) {
1277: custom = new BasicCustomEditor(this );
1278: }
1279: return custom;
1280: }
1281:
1282: public void vetoNext() {
1283: env.setState(env.STATE_NEEDS_VALIDATION);
1284: vetoNextChange = true;
1285: System.err.println(" veto next");
1286: }
1287:
1288: public void propertyChange(PropertyChangeEvent evt) {
1289:
1290: }
1291:
1292: boolean vetoNextChange = false;
1293:
1294: public void vetoableChange(PropertyChangeEvent e)
1295: throws PropertyVetoException {
1296: System.err.println("GOT A VETOABLE CHANGE IN BASIC EDITOR");
1297: PropertyEnv env = (PropertyEnv) e.getSource();
1298: if ((vetoNextChange || "Dont allow validate"
1299: .equals(getAsText()))
1300: && PropertyEnv.STATE_NEEDS_VALIDATION.equals(env
1301: .getState())) {
1302: System.err.println(" VETOING");
1303: PropertyVetoException pve = new PropertyVetoException(
1304: "NoNoNoNoNo", e);
1305: ErrorManager.getDefault().annotate(pve,
1306: ErrorManager.USER, null, "You can't do that!",
1307: null, null);
1308: vetoNextChange = false;
1309: throw pve;
1310: }
1311: }
1312:
1313: public void setAsText(String s) {
1314: System.err.println(" BasicEditor.setAsText: " + s);
1315: if ("invalidValue".equals(s)) {
1316: IllegalArgumentException iae = new IllegalArgumentException();
1317: ErrorManager.getDefault().annotate(iae,
1318: ErrorManager.USER, "invalid value", "No way",
1319: null, null);
1320: throw iae;
1321: }
1322: setValue(s);
1323: }
1324:
1325: }
1326:
1327: public class BasicCustomEditor extends JPanel implements
1328: ActionListener {
1329: JTextField valueField = new JTextField();
1330: JButton setInvalidValueButton = new JButton("Invalid value");
1331: JButton setDontAllowValidateButton = new JButton(
1332: "Dont allow validate");
1333: BasicEditor editor;
1334:
1335: public BasicCustomEditor(BasicEditor editor) {
1336: this .editor = editor;
1337: init();
1338: }
1339:
1340: private void init() {
1341: setLayout(new FlowLayout());
1342: valueField.addActionListener(this );
1343: setInvalidValueButton.addActionListener(this );
1344: setDontAllowValidateButton.addActionListener(this );
1345: valueField.setColumns(30);
1346: setBackground(Color.ORANGE);
1347: add(valueField);
1348: add(setInvalidValueButton);
1349: add(setDontAllowValidateButton);
1350: }
1351:
1352: boolean processing;
1353:
1354: public void actionPerformed(ActionEvent e) {
1355: processing = true;
1356: try {
1357: if (e.getSource() == setDontAllowValidateButton) {
1358: editor.vetoNext();
1359: valueField.setText("dont allow validate");
1360: }
1361: if (e.getSource() == setInvalidValueButton) {
1362: valueField.setText("invalidValue");
1363: }
1364: if (e.getSource() == valueField) {
1365: editor.setAsText(valueField.getText());
1366: }
1367: editor.env.setState(PropertyEnv.STATE_NEEDS_VALIDATION);
1368: } finally {
1369: processing = false;
1370: }
1371: }
1372: }
1373: }
|