Lines 42-224
Link Here
|
42 |
package org.netbeans.core; |
42 |
package org.netbeans.core; |
43 |
|
43 |
|
44 |
import java.awt.event.ActionEvent; |
44 |
import java.awt.event.ActionEvent; |
45 |
import java.beans.PropertyChangeEvent; |
45 |
import java.awt.event.KeyEvent; |
46 |
import java.beans.PropertyChangeListener; |
46 |
import java.io.IOException; |
|
|
47 |
import java.io.OutputStream; |
47 |
import java.util.Arrays; |
48 |
import java.util.Arrays; |
48 |
import java.util.Collections; |
49 |
import java.util.Collections; |
49 |
import java.util.HashMap; |
50 |
import java.util.concurrent.atomic.AtomicReference; |
50 |
import java.util.Map; |
|
|
51 |
import java.util.Observable; |
52 |
import java.util.Observer; |
53 |
import javax.swing.AbstractAction; |
51 |
import javax.swing.AbstractAction; |
54 |
import javax.swing.Action; |
52 |
import javax.swing.Action; |
55 |
import javax.swing.KeyStroke; |
53 |
import javax.swing.KeyStroke; |
56 |
import javax.swing.text.Keymap; |
54 |
import javax.swing.text.Keymap; |
|
|
55 |
import org.netbeans.junit.MockServices; |
57 |
import org.netbeans.junit.NbTestCase; |
56 |
import org.netbeans.junit.NbTestCase; |
|
|
57 |
import org.openide.filesystems.FileObject; |
58 |
import org.openide.filesystems.FileUtil; |
59 |
import org.openide.loaders.DataFolder; |
60 |
import org.openide.loaders.DataObject; |
61 |
import org.openide.loaders.DataShadow; |
62 |
import org.openide.loaders.Environment; |
63 |
import org.openide.loaders.InstanceSupport; |
64 |
import org.openide.loaders.XMLDataObject; |
65 |
import org.openide.util.HelpCtx; |
66 |
import org.openide.util.Lookup; |
67 |
import org.openide.util.actions.CallableSystemAction; |
68 |
import org.openide.util.lookup.Lookups; |
69 |
import org.w3c.dom.Document; |
58 |
|
70 |
|
59 |
/** Test NbKeymap. |
|
|
60 |
* @author Jesse Glick |
61 |
* @see "#30455" */ |
62 |
public class NbKeymapTest extends NbTestCase { |
71 |
public class NbKeymapTest extends NbTestCase { |
63 |
public NbKeymapTest(String name) { |
72 |
public NbKeymapTest(String name) { |
64 |
super(name); |
73 |
super(name); |
65 |
} |
74 |
} |
66 |
|
75 |
|
67 |
@Override |
76 |
static { |
68 |
protected boolean runInEQ () { |
77 |
System.setProperty("os.name", "Linux"); // just to standardize modifier key binding |
69 |
return true; |
78 |
} |
|
|
79 |
|
80 |
protected @Override void setUp() throws Exception { |
81 |
for (FileObject f : FileUtil.getConfigRoot().getChildren()) { |
82 |
f.delete(); |
83 |
} |
70 |
} |
84 |
} |
71 |
|
85 |
|
72 |
public void testBasicFunctionality() throws Exception { |
86 |
private FileObject make(String path) throws IOException { |
73 |
Keymap km = new NbKeymap(); |
87 |
return FileUtil.createData(FileUtil.getConfigRoot(), path); |
74 |
Action a1 = new DummyAction("a1"); |
|
|
75 |
Action a2 = new DummyAction("a2"); |
76 |
Action d = new DummyAction("d"); |
77 |
KeyStroke k1 = KeyStroke.getKeyStroke("X"); |
78 |
KeyStroke k2 = KeyStroke.getKeyStroke("Y"); |
79 |
assertFalse(k1.equals(k2)); |
80 |
assertNull(km.getAction(k1)); |
81 |
assertNull(km.getAction(k2)); |
82 |
assertEquals(Collections.EMPTY_LIST, Arrays.asList(km.getBoundActions())); |
83 |
assertEquals(Collections.EMPTY_LIST, Arrays.asList(km.getBoundKeyStrokes())); |
84 |
assertNull(km.getDefaultAction()); |
85 |
km.setDefaultAction(d); |
86 |
assertEquals(d, km.getDefaultAction()); |
87 |
km.addActionForKeyStroke(k1, a1); |
88 |
assertEquals(a1, km.getAction(k1)); |
89 |
assertTrue(km.isLocallyDefined(k1)); |
90 |
assertEquals(null, km.getAction(k2)); |
91 |
assertEquals(Collections.singletonList(a1), Arrays.asList(km.getBoundActions())); |
92 |
assertEquals(Collections.singletonList(k1), Arrays.asList(km.getBoundKeyStrokes())); |
93 |
km.addActionForKeyStroke(k2, a2); |
94 |
assertEquals(a1, km.getAction(k1)); |
95 |
assertEquals(a2, km.getAction(k2)); |
96 |
assertEquals(2, km.getBoundActions().length); |
97 |
assertEquals(2, km.getBoundKeyStrokes().length); |
98 |
km.addActionForKeyStroke(k1, d); |
99 |
assertEquals(d, km.getAction(k1)); |
100 |
assertEquals(a2, km.getAction(k2)); |
101 |
assertEquals(2, km.getBoundActions().length); |
102 |
assertEquals(2, km.getBoundKeyStrokes().length); |
103 |
assertEquals(Collections.EMPTY_LIST, Arrays.asList(km.getKeyStrokesForAction(a1))); |
104 |
assertEquals(Collections.singletonList(k2), Arrays.asList(km.getKeyStrokesForAction(a2))); |
105 |
assertEquals(Collections.singletonList(k1), Arrays.asList(km.getKeyStrokesForAction(d))); |
106 |
km.removeKeyStrokeBinding(k2); |
107 |
assertEquals(d, km.getAction(k1)); |
108 |
assertNull(km.getAction(k2)); |
109 |
assertEquals(Collections.singletonList(d), Arrays.asList(km.getBoundActions())); |
110 |
assertEquals(Collections.singletonList(k1), Arrays.asList(km.getBoundKeyStrokes())); |
111 |
km.removeBindings(); |
112 |
assertNull(km.getAction(k1)); |
113 |
assertNull(km.getAction(k2)); |
114 |
assertEquals(Collections.EMPTY_LIST, Arrays.asList(km.getBoundActions())); |
115 |
assertEquals(Collections.EMPTY_LIST, Arrays.asList(km.getBoundKeyStrokes())); |
116 |
} |
88 |
} |
117 |
|
89 |
|
118 |
public void testObservability() throws Exception { |
90 |
private FileObject makeFolder(String path) throws IOException { |
119 |
NbKeymap km = new NbKeymap(); |
91 |
return FileUtil.createFolder(FileUtil.getConfigRoot(), path); |
120 |
O o = new O(); |
92 |
} |
121 |
km.addObserver(o); |
93 |
|
122 |
assertFalse(o.changed); |
94 |
private void assertMapping(Keymap km, KeyStroke stroke, FileObject presenterDefinition, String actionName) throws Exception { |
123 |
Action a1 = new DummyAction("a1"); |
95 |
Action a = km.getAction(stroke); |
124 |
Action a2 = new DummyAction("a2"); |
96 |
assertNotNull("for " + stroke, a); |
125 |
KeyStroke k1 = KeyStroke.getKeyStroke("X"); |
97 |
assertEquals(actionName, a.getValue(Action.NAME)); |
126 |
km.addActionForKeyStroke(k1, a1); |
98 |
a.putValue("definingFile", presenterDefinition); |
127 |
assertTrue(o.changed); |
99 |
assertEquals("for " + stroke + " from " + presenterDefinition.getPath(), |
128 |
o.changed = false; |
100 |
Collections.singletonList(stroke), Arrays.asList(km.getKeyStrokesForAction(a))); |
129 |
km.addActionForKeyStroke(k1, a2); |
|
|
130 |
assertTrue(o.changed); |
131 |
o.changed = false; |
132 |
km.removeKeyStrokeBinding(k1); |
133 |
assertTrue(o.changed); |
134 |
} |
101 |
} |
135 |
|
102 |
|
136 |
public void testAcceleratorMapping() throws Exception { |
103 |
public void testAcceleratorMapping() throws Exception { |
|
|
104 |
FileObject def1 = make("Actions/DummyAction1.instance"); |
105 |
def1.setAttribute("instanceCreate", new DummyAction("one")); |
106 |
FileObject def2 = make("Actions/DummyAction2.instance"); |
107 |
def2.setAttribute("instanceCreate", new DummyAction("two")); |
108 |
FileObject def3 = make("Actions/DummySystemAction1.instance"); |
109 |
def3.setAttribute("instanceClass", DummySystemAction1.class.getName()); |
110 |
FileObject def4 = make("Actions/" + DummySystemAction2.class.getName().replace('.', '-') + ".instance"); |
111 |
DataFolder shortcuts = DataFolder.findFolder(makeFolder("Shortcuts")); |
112 |
DataShadow.create(shortcuts, "1", DataObject.find(def1)).getPrimaryFile(); |
113 |
DataShadow.create(shortcuts, "2", DataObject.find(def2)).getPrimaryFile(); |
114 |
DataShadow.create(shortcuts, "3", DataObject.find(def3)).getPrimaryFile(); |
115 |
DataShadow.create(shortcuts, "C-4", DataObject.find(def4)).getPrimaryFile(); |
116 |
DataFolder menu = DataFolder.findFolder(makeFolder("Menu/Tools")); |
117 |
FileObject menuitem1 = DataShadow.create(menu, "whatever1", DataObject.find(def1)).getPrimaryFile(); |
118 |
FileObject menuitem2 = DataShadow.create(menu, "whatever2", DataObject.find(def2)).getPrimaryFile(); |
119 |
FileObject menuitem3 = DataShadow.create(menu, "whatever3", DataObject.find(def3)).getPrimaryFile(); |
120 |
FileObject menuitem4 = DataShadow.create(menu, "whatever4", DataObject.find(def4)).getPrimaryFile(); |
137 |
Keymap km = new NbKeymap(); |
121 |
Keymap km = new NbKeymap(); |
138 |
Action a1 = new DummyAction("a1"); |
122 |
assertMapping(km, KeyStroke.getKeyStroke(KeyEvent.VK_1, 0), menuitem1, "one"); |
139 |
Action a2 = new DummyAction("a2"); |
123 |
assertMapping(km, KeyStroke.getKeyStroke(KeyEvent.VK_2, 0), menuitem2, "two"); |
140 |
KeyStroke k1 = KeyStroke.getKeyStroke("X"); |
124 |
assertMapping(km, KeyStroke.getKeyStroke(KeyEvent.VK_3, 0), menuitem3, "DummySystemAction1"); |
141 |
KeyStroke k2 = KeyStroke.getKeyStroke("Y"); |
125 |
assertMapping(km, KeyStroke.getKeyStroke(KeyEvent.VK_4, KeyEvent.CTRL_MASK), menuitem4, "DummySystemAction2"); |
142 |
assertNull(a1.getValue(Action.ACCELERATOR_KEY)); |
126 |
} |
143 |
assertNull(a2.getValue(Action.ACCELERATOR_KEY)); |
127 |
|
144 |
AccL l = new AccL(); |
128 |
public void testMultipleAcceleratorMapping() throws Exception { |
145 |
a1.addPropertyChangeListener(l); |
129 |
// XXX |
146 |
assertFalse(l.changed); |
130 |
// create >1 registration and test that most basic is returned, e.g. Ctrl-V over Paste |
147 |
km.addActionForKeyStroke(k1, a1); |
|
|
148 |
assertEquals(k1, a1.getValue(Action.ACCELERATOR_KEY)); |
149 |
assertTrue(l.changed); |
150 |
l.changed = false; |
151 |
km.addActionForKeyStroke(k2, a2); |
152 |
assertEquals(k2, a2.getValue(Action.ACCELERATOR_KEY)); |
153 |
km.addActionForKeyStroke(k2, a1); |
154 |
Object acc = a1.getValue(Action.ACCELERATOR_KEY); |
155 |
assertTrue(acc == k1 || acc == k2); |
156 |
assertNull(a2.getValue(Action.ACCELERATOR_KEY)); |
157 |
km.removeKeyStrokeBinding(k1); |
158 |
assertEquals(k2, a1.getValue(Action.ACCELERATOR_KEY)); |
159 |
km.removeKeyStrokeBinding(k2); |
160 |
assertNull(a1.getValue(Action.ACCELERATOR_KEY)); |
161 |
assertTrue(l.changed); |
162 |
} |
131 |
} |
163 |
|
132 |
|
164 |
public void testAddActionForKeyStrokeMap() throws Exception { |
133 |
public void testUnusualInstanceFileExtensions() throws Exception { |
165 |
NbKeymap km = new NbKeymap(); |
134 |
MockServices.setServices(ENV.class); |
166 |
O o = new O(); |
135 |
FileObject inst = make("Shortcuts/C-F11.xml"); |
167 |
km.addObserver(o); |
136 |
OutputStream os = inst.getOutputStream(); |
168 |
Action a1 = new DummyAction("a1"); |
137 |
os.write("<action/>".getBytes()); |
169 |
Action a2 = new DummyAction("a2"); |
138 |
os.close(); |
170 |
Action a3 = new DummyAction("a3"); |
139 |
assertMapping(new NbKeymap(), KeyStroke.getKeyStroke(KeyEvent.VK_F11, KeyEvent.CTRL_MASK), inst, "whatever"); |
171 |
KeyStroke k1 = KeyStroke.getKeyStroke("X"); |
140 |
} |
172 |
KeyStroke k2 = KeyStroke.getKeyStroke("Y"); |
141 |
|
173 |
Map<KeyStroke,Action> m = new HashMap<KeyStroke,Action>(); |
142 |
public void testAbstractModifiers() throws Exception { |
174 |
m.put(k1, a1); |
143 |
Keymap km = new NbKeymap(); |
175 |
m.put(k2, a2); |
144 |
FileObject inst1 = make("Shortcuts/D-1.instance"); |
176 |
km.addActionForKeyStrokeMap(m); |
145 |
inst1.setAttribute("instanceCreate", new DummyAction("one")); |
177 |
assertTrue(o.changed); |
146 |
FileObject inst2 = make("Shortcuts/O-1.instance"); |
178 |
assertEquals(a1, km.getAction(k1)); |
147 |
inst2.setAttribute("instanceCreate", new DummyAction("two")); |
179 |
assertEquals(a2, km.getAction(k2)); |
148 |
assertMapping(km, KeyStroke.getKeyStroke(KeyEvent.VK_1, KeyEvent.CTRL_MASK), inst1, "one"); |
180 |
assertEquals(k1, a1.getValue(Action.ACCELERATOR_KEY)); |
149 |
assertMapping(km, KeyStroke.getKeyStroke(KeyEvent.VK_1, KeyEvent.ALT_MASK), inst2, "two"); |
181 |
assertEquals(k2, a2.getValue(Action.ACCELERATOR_KEY)); |
150 |
} |
182 |
assertEquals(2, km.getBoundActions().length); |
151 |
|
183 |
assertEquals(2, km.getBoundKeyStrokes().length); |
152 |
public void testDifferentKeymaps() throws Exception { |
184 |
km.removeBindings(); |
153 |
// XXX |
185 |
km.addActionForKeyStroke(k1, a3); |
154 |
// Switch to various keymaps and make sure getAction works. |
186 |
km.addActionForKeyStrokeMap(m); |
155 |
// Existing actions ought to have their accelerators changed if you change keymap. |
187 |
assertEquals(a1, km.getAction(k1)); |
156 |
} |
188 |
assertEquals(a2, km.getAction(k2)); |
157 |
|
189 |
assertEquals(k1, a1.getValue(Action.ACCELERATOR_KEY)); |
158 |
public void testMultiKeyShortcuts() throws Exception { |
190 |
assertEquals(k2, a2.getValue(Action.ACCELERATOR_KEY)); |
159 |
final AtomicReference<String> ran = new AtomicReference<String>(); |
191 |
assertNull(a3.getValue(Action.ACCELERATOR_KEY)); |
160 |
class A extends AbstractAction { |
192 |
assertEquals(2, km.getBoundActions().length); |
161 |
final String s; |
193 |
assertEquals(2, km.getBoundKeyStrokes().length); |
162 |
A(String s) { |
|
|
163 |
this.s = s; |
164 |
} |
165 |
public void actionPerformed(ActionEvent e) { |
166 |
ran.set(s); |
167 |
} |
168 |
} |
169 |
make("Shortcuts/C-X 1.instance").setAttribute("instanceCreate", new A("C-X 1")); |
170 |
make("Shortcuts/C-X 2.instance").setAttribute("instanceCreate", new A("C-X 2")); |
171 |
make("Shortcuts/C-U A B.instance").setAttribute("instanceCreate", new A("C-U A B")); |
172 |
Keymap km = new NbKeymap(); |
173 |
Action a = km.getAction(KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.CTRL_MASK)); |
174 |
assertNotNull(a); |
175 |
a.actionPerformed(null); |
176 |
assertEquals(null, ran.getAndSet(null)); |
177 |
a = km.getAction(KeyStroke.getKeyStroke(KeyEvent.VK_1, 0)); |
178 |
assertNotNull(a); |
179 |
a.actionPerformed(null); |
180 |
assertEquals("C-X 1", ran.getAndSet(null)); |
181 |
a = km.getAction(KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyEvent.CTRL_MASK)); |
182 |
assertNotNull(a); |
183 |
a.actionPerformed(null); |
184 |
assertEquals(null, ran.getAndSet(null)); |
185 |
a = km.getAction(KeyStroke.getKeyStroke(KeyEvent.VK_2, 0)); |
186 |
assertNotNull(a); |
187 |
a.actionPerformed(null); |
188 |
assertEquals("C-X 2", ran.getAndSet(null)); |
189 |
a = km.getAction(KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyEvent.CTRL_MASK)); |
190 |
assertNotNull(a); |
191 |
a.actionPerformed(null); |
192 |
assertEquals(null, ran.getAndSet(null)); |
193 |
a = km.getAction(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0)); |
194 |
assertNotNull(a); |
195 |
a.actionPerformed(null); |
196 |
assertEquals(null, ran.getAndSet(null)); |
197 |
a = km.getAction(KeyStroke.getKeyStroke(KeyEvent.VK_B, 0)); |
198 |
assertNotNull(a); |
199 |
a.actionPerformed(null); |
200 |
assertEquals("C-U A B", ran.getAndSet(null)); |
201 |
} |
202 |
|
203 |
public void testChangesInShortcutRegistrations() throws Exception { |
204 |
// XXX |
205 |
// Add, remove shortcut registrations and see what happens. |
206 |
} |
207 |
|
208 |
private static final class DummyAction extends AbstractAction { |
209 |
public DummyAction(String name) { |
210 |
super(name); |
211 |
} |
212 |
public void actionPerformed(ActionEvent e) {} |
194 |
} |
213 |
} |
195 |
|
214 |
|
196 |
private static final class DummyAction extends AbstractAction { |
215 |
public static class ENV extends Object implements Environment.Provider { |
197 |
private final String name; |
216 |
public Lookup getEnvironment(DataObject obj) { |
198 |
public DummyAction(String name) { |
217 |
if (obj instanceof XMLDataObject) { |
199 |
this.name = name; |
218 |
try { |
200 |
} |
219 |
Document doc = ((XMLDataObject) obj).getDocument(); |
201 |
public void actionPerformed(ActionEvent e) {} |
220 |
if (doc.getDocumentElement().getNodeName().equals("action")) { |
202 |
@Override |
221 |
return Lookups.singleton(new InstanceSupport.Instance(new DummyAction("whatever"))); |
203 |
public String toString() { |
222 |
} |
204 |
return "DummyAction[" + name + "]"; |
223 |
} catch (Exception ex) { |
|
|
224 |
ex.printStackTrace(); |
225 |
fail("No exception: " + ex.getMessage()); |
226 |
} |
227 |
} |
228 |
return Lookup.EMPTY; |
205 |
} |
229 |
} |
206 |
} |
230 |
} |
207 |
|
231 |
|
208 |
private static final class O implements Observer { |
232 |
public static final class DummySystemAction1 extends CallableSystemAction { |
209 |
public boolean changed = false; |
233 |
public void performAction() {} |
210 |
public void update(Observable o, Object arg) { |
234 |
public String getName() { |
211 |
changed = true; |
235 |
return "DummySystemAction1"; |
|
|
236 |
} |
237 |
public HelpCtx getHelpCtx() { |
238 |
return null; |
212 |
} |
239 |
} |
213 |
} |
240 |
} |
214 |
|
241 |
|
215 |
private static final class AccL implements PropertyChangeListener { |
242 |
public static final class DummySystemAction2 extends CallableSystemAction { |
216 |
public boolean changed = false; |
243 |
public void performAction() {} |
217 |
public void propertyChange(PropertyChangeEvent evt) { |
244 |
public String getName() { |
218 |
if (Action.ACCELERATOR_KEY.equals(evt.getPropertyName())) { |
245 |
return "DummySystemAction2"; |
219 |
changed = true; |
246 |
} |
220 |
} |
247 |
public HelpCtx getHelpCtx() { |
|
|
248 |
return null; |
221 |
} |
249 |
} |
222 |
} |
250 |
} |
223 |
|
251 |
|
224 |
} |
252 |
} |