001: /*
002: * Sun Public License Notice
003: *
004: * The contents of this file are subject to the Sun Public License
005: * Version 1.0 (the "License"). You may not use this file except in
006: * compliance with the License. A copy of the License is available at
007: * http://www.sun.com/
008: *
009: * The Original Code is NetBeans. The Initial Developer of the Original
010: * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
011: * Microsystems, Inc. All Rights Reserved.
012: */
013:
014: package org.netbeans.editor;
015:
016: import java.awt.Component;
017: import java.awt.Dialog;
018: import java.awt.Dimension;
019: import java.awt.event.ActionEvent;
020: import java.awt.event.ActionListener;
021: import java.beans.PropertyChangeEvent;
022: import java.beans.PropertyChangeListener;
023: import java.text.MessageFormat;
024: import java.util.ArrayList;
025: import java.util.Iterator;
026: import java.util.List;
027: import java.util.Vector;
028:
029: import javax.swing.JButton;
030: import javax.swing.JLabel;
031: import javax.swing.JList;
032: import javax.swing.KeyStroke;
033: import javax.swing.ListCellRenderer;
034:
035: /**
036: * The component for displaying and editing just recorded macro. It allows you
037: * to define a name for the macro and bound keystrokes to it.
038: *
039: * @author Petr Nejedly
040: * @version 1.0
041: */
042: public class MacroSavePanel extends javax.swing.JPanel {
043:
044: private Vector bindings = new Vector();
045: private Class kitClass;
046:
047: /** Creates new form SaveMacroPanel */
048: public MacroSavePanel(Class kitClass) {
049: this .kitClass = kitClass;
050: initComponents();
051:
052: nameLabel.setDisplayedMnemonic(LocaleSupport.getString(
053: "MSP_Name_Mnemonic").charAt(0)); // NOI18N
054: macroLabel.setDisplayedMnemonic(LocaleSupport.getString(
055: "MSP_Macro_Mnemonic").charAt(0)); // NOI18N
056: bindingLabel.setDisplayedMnemonic(LocaleSupport.getString(
057: "MSP_Keys_Mnemonic").charAt(0)); // NOI18N
058: nameField.getAccessibleContext().setAccessibleDescription(
059: LocaleSupport.getString("ACSD_MSP_Name")); // NOI18N
060: macroField.getAccessibleContext().setAccessibleDescription(
061: LocaleSupport.getString("ACSD_MSP_Macro")); // NOI18N
062: bindingList.getAccessibleContext().setAccessibleDescription(
063: LocaleSupport.getString("ACSD_MSP_Keys")); // NOI18N
064: getAccessibleContext().setAccessibleName(
065: LocaleSupport.getString("MDS_Title")); // NOI18N
066: getAccessibleContext().setAccessibleDescription(
067: LocaleSupport.getString("ACSD_MSP")); // NOI18N
068:
069: // temporary loss of function
070: setMaximumSize(new Dimension(400, 200));
071: }
072:
073: public Dimension getPreferredSize() {
074: Dimension pref = super .getPreferredSize();
075: Dimension max = getMaximumSize();
076: if (pref.width > max.width)
077: pref.width = max.width;
078: if (pref.height > max.height)
079: pref.height = max.height;
080: return pref;
081: }
082:
083: private void initComponents() {// GEN-BEGIN:initComponents
084: java.awt.GridBagConstraints gridBagConstraints;
085:
086: macroPanel = new javax.swing.JPanel();
087: nameLabel = new javax.swing.JLabel();
088: macroLabel = new javax.swing.JLabel();
089: nameField = new javax.swing.JTextField();
090: macroField = new javax.swing.JTextField();
091: bindingPanel = new javax.swing.JPanel();
092: bindingLabel = new javax.swing.JLabel();
093: bindingScrollPane = new javax.swing.JScrollPane();
094: bindingList = new javax.swing.JList();
095: addButton = new javax.swing.JButton();
096: removeButton = new javax.swing.JButton();
097:
098: setLayout(new java.awt.GridBagLayout());
099:
100: setBorder(new javax.swing.border.EmptyBorder(
101: new java.awt.Insets(12, 12, 11, 11)));
102: macroPanel.setLayout(new java.awt.GridBagLayout());
103:
104: nameLabel.setText(LocaleSupport.getString("MSP_Name", "Name"));
105: nameLabel.setLabelFor(nameField);
106: gridBagConstraints = new java.awt.GridBagConstraints();
107: gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 12);
108: gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
109: macroPanel.add(nameLabel, gridBagConstraints);
110:
111: macroLabel.setText(LocaleSupport
112: .getString("MSP_Macro", "Macro"));
113: macroLabel.setLabelFor(macroField);
114: gridBagConstraints = new java.awt.GridBagConstraints();
115: gridBagConstraints.gridx = 0;
116: gridBagConstraints.gridy = 1;
117: gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 12);
118: gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
119: macroPanel.add(macroLabel, gridBagConstraints);
120:
121: gridBagConstraints = new java.awt.GridBagConstraints();
122: gridBagConstraints.gridx = 1;
123: gridBagConstraints.gridy = 0;
124: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
125: gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
126: gridBagConstraints.weightx = 1.0;
127: macroPanel.add(nameField, gridBagConstraints);
128:
129: gridBagConstraints = new java.awt.GridBagConstraints();
130: gridBagConstraints.gridx = 1;
131: gridBagConstraints.gridy = 1;
132: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
133: gridBagConstraints.insets = new java.awt.Insets(5, 0, 0, 0);
134: gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
135: gridBagConstraints.weightx = 1.0;
136: macroPanel.add(macroField, gridBagConstraints);
137:
138: gridBagConstraints = new java.awt.GridBagConstraints();
139: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
140: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
141: add(macroPanel, gridBagConstraints);
142:
143: bindingPanel.setLayout(new java.awt.GridBagLayout());
144:
145: bindingLabel.setText(LocaleSupport.getString("MSP_Keys",
146: "Keybindings:"));
147: bindingLabel.setLabelFor(bindingList);
148: gridBagConstraints = new java.awt.GridBagConstraints();
149: gridBagConstraints.insets = new java.awt.Insets(0, 0, 2, 0);
150: gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
151: bindingPanel.add(bindingLabel, gridBagConstraints);
152:
153: bindingList.setCellRenderer(new KeySequenceCellRenderer());
154: bindingScrollPane.setViewportView(bindingList);
155:
156: gridBagConstraints = new java.awt.GridBagConstraints();
157: gridBagConstraints.gridx = 0;
158: gridBagConstraints.gridy = 1;
159: gridBagConstraints.gridheight = 3;
160: gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
161: gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 12);
162: gridBagConstraints.weightx = 1.0;
163: gridBagConstraints.weighty = 1.0;
164: bindingPanel.add(bindingScrollPane, gridBagConstraints);
165:
166: addButton.setToolTipText(LocaleSupport.getString(
167: "MSP_AddToolTip", "Add a keybinding for this macro."));
168: addButton.setMnemonic(LocaleSupport.getString(
169: "MSP_Add_Mnemonic").charAt(0));
170: addButton.setText(LocaleSupport.getString("MSP_Add", "Add..."));
171: addButton
172: .addActionListener(new java.awt.event.ActionListener() {
173: public void actionPerformed(
174: java.awt.event.ActionEvent evt) {
175: addBindingActionPerformed(evt);
176: }
177: });
178:
179: gridBagConstraints = new java.awt.GridBagConstraints();
180: gridBagConstraints.gridx = 1;
181: gridBagConstraints.gridy = 1;
182: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
183: gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 0);
184: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
185: bindingPanel.add(addButton, gridBagConstraints);
186:
187: removeButton.setToolTipText(LocaleSupport.getString(
188: "MSP_RemoveToolTip",
189: "Remove a keybinding from this macro."));
190: removeButton.setMnemonic(LocaleSupport.getString(
191: "MSP_Remove_Mnemonic").charAt(0));
192: removeButton.setText(LocaleSupport.getString("MSP_Remove",
193: "Remove"));
194: removeButton.setEnabled(false);
195: removeButton
196: .addActionListener(new java.awt.event.ActionListener() {
197: public void actionPerformed(
198: java.awt.event.ActionEvent evt) {
199: removeBindingActionPerformed(evt);
200: }
201: });
202:
203: gridBagConstraints = new java.awt.GridBagConstraints();
204: gridBagConstraints.gridx = 1;
205: gridBagConstraints.gridy = 2;
206: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
207: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
208: bindingPanel.add(removeButton, gridBagConstraints);
209:
210: gridBagConstraints = new java.awt.GridBagConstraints();
211: gridBagConstraints.gridx = 0;
212: gridBagConstraints.gridy = 1;
213: gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
214: gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0);
215: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
216: gridBagConstraints.weightx = 1.0;
217: gridBagConstraints.weighty = 1.0;
218: add(bindingPanel, gridBagConstraints);
219:
220: }// GEN-END:initComponents
221:
222: private void removeBindingActionPerformed(
223: java.awt.event.ActionEvent evt) {// GEN-FIRST:event_removeBindingActionPerformed
224: int index = bindingList.getSelectedIndex();
225: if (index >= 0) {
226: bindings.remove(index);
227: bindingList.setListData(bindings);
228: }
229: if (bindingList.getModel().getSize() <= 0)
230: removeButton.setEnabled(false);
231: else
232: bindingList.setSelectedIndex(0);
233: }// GEN-LAST:event_removeBindingActionPerformed
234:
235: private void addBindingActionPerformed(
236: java.awt.event.ActionEvent evt) {// GEN-FIRST:event_addBindingActionPerformed
237: KeyStroke[] newKeyStrokes = new KeySequenceRequester()
238: .getKeySequence();
239:
240: if (newKeyStrokes != null) {
241: bindings.add(newKeyStrokes);
242: bindingList.setListData(bindings);
243: bindingList.setSelectedIndex(0);
244: removeButton.setEnabled(true);
245: }
246: }// GEN-LAST:event_addBindingActionPerformed
247:
248: public String getName() {
249: return nameField.getText();
250: }
251:
252: public void setName(String name) {
253: nameField.setText(name);
254: }
255:
256: public String getBody() {
257: return macroField.getText();
258: }
259:
260: public void setBody(String body) {
261: macroField.setText(body);
262: }
263:
264: /** @return List of KeyStroke[] */
265: public List getKeySequences() {
266: return new ArrayList(bindings);
267: }
268:
269: /**
270: * @param sequences
271: * List of KeyStroke[] bounds to this macro
272: */
273: public void setKeySequences(List sequences) {
274: bindings = new Vector(sequences);
275: bindingList.setListData(bindings);
276: }
277:
278: // Variables declaration - do not modify//GEN-BEGIN:variables
279: private javax.swing.JLabel nameLabel;
280: private javax.swing.JTextField nameField;
281: private javax.swing.JScrollPane bindingScrollPane;
282: private javax.swing.JPanel macroPanel;
283: private javax.swing.JButton addButton;
284: private javax.swing.JList bindingList;
285: private javax.swing.JPanel bindingPanel;
286: private javax.swing.JLabel macroLabel;
287: private javax.swing.JTextField macroField;
288: private javax.swing.JLabel bindingLabel;
289: private javax.swing.JButton removeButton;
290:
291: // End of variables declaration//GEN-END:variables
292:
293: public void popupNotify() {
294: nameField.requestFocus();
295: }
296:
297: private class KeySequenceCellRenderer extends JLabel implements
298: ListCellRenderer {
299: public KeySequenceCellRenderer() {
300: setOpaque(true);
301: }
302:
303: public Component getListCellRendererComponent(JList list,
304: Object value, int index, boolean isSelected,
305: boolean cellHasFocus) {
306: setText(Utilities.keySequenceToString((KeyStroke[]) value));
307: setBackground(isSelected ? list.getSelectionBackground()
308: : list.getBackground());
309: setForeground(isSelected ? list.getSelectionForeground()
310: : list.getForeground());
311: return this ;
312: }
313: }
314:
315: /**
316: * Encapsulation for components of dialog asking for new KeySequence
317: */
318: class KeySequenceRequester {
319:
320: KeySequenceInputPanel panel;
321: Dialog dial;
322:
323: JButton[] buttons = {
324: new JButton(LocaleSupport.getString("MSP_ok")), // NOI18N
325: new JButton(LocaleSupport.getString("MSP_clear")), // NOI18N
326: new JButton(LocaleSupport.getString("MSP_cancel")) }; // NOI18N
327:
328: KeyStroke[] retVal = null;
329:
330: KeySequenceRequester() {
331: ((JButton) buttons[0]).getAccessibleContext()
332: .setAccessibleDescription(
333: LocaleSupport.getString("ACSD_MSP_ok")); // NOI18N
334: ((JButton) buttons[1]).getAccessibleContext()
335: .setAccessibleDescription(
336: LocaleSupport.getString("ACSD_MSP_clear")); // NOI18N
337: ((JButton) buttons[2]).getAccessibleContext()
338: .setAccessibleDescription(
339: LocaleSupport.getString("ACSD_MSP_cancel")); // NOI18N
340: ((JButton) buttons[1]).setMnemonic(LocaleSupport.getString(
341: "MSP_clear_Mnemonic").charAt(0)); // NOI18N
342: ((JButton) buttons[0]).setEnabled(false); // default initial state
343:
344: // Prepare KeySequence input dialog
345: panel = new KeySequenceInputPanel();
346: panel
347: .addPropertyChangeListener(new PropertyChangeListener() {
348: public void propertyChange(
349: PropertyChangeEvent evt) {
350: if (KeySequenceInputPanel.PROP_KEYSEQUENCE != evt
351: .getPropertyName())
352: return;
353: KeyStroke[] seq = panel.getKeySequence();
354: String warn = isAlreadyBounded(seq);
355: if (warn == null)
356: warn = getCollisionString(seq);
357: ((JButton) buttons[0])
358: .setEnabled(seq.length > 0
359: && warn == null);
360: panel.setInfoText(warn == null ? "" : warn); // NOI18N
361: }
362: });
363:
364: dial = DialogSupport.createDialog(
365: LocaleSupport.getString("MSP_AddTitle"), // NOI18N
366: panel, true, buttons, false, -1, 2,
367: new ActionListener() {
368: public void actionPerformed(ActionEvent evt) {
369: if (evt.getSource() == buttons[1]) { // Clear
370: // pressed
371: panel.clear(); // Clear entered KeyStrokes,
372: // start again
373: panel.requestFocus(); // Make user imediately
374: // able to enter new
375: // strokes
376: } else if (evt.getSource() == buttons[0]) { // OK
377: // pressed
378: retVal = panel.getKeySequence();
379: dial.dispose(); // Done
380: } else if (evt.getSource() == buttons[2]) { // OK
381: // pressed
382: retVal = null;
383: dial.dispose(); // Done
384: }
385: }
386: });
387:
388: }
389:
390: KeyStroke[] getKeySequence() {
391: dial.pack();
392: panel.requestFocus();
393: dial.show();
394: return retVal;
395: }
396:
397: /**
398: * Check whether this KeyStroke is already bounded to this macro or not.
399: * Disallow to duplicate the KeyStroke.
400: */
401: String isAlreadyBounded(KeyStroke[] seq) {
402: if (seq.length == 0)
403: return null; // NOI18N not valid sequence, but don't alert
404: // user
405:
406: Iterator it = bindings.iterator();
407: while (it.hasNext()) {
408: if (isOverlapingSequence((KeyStroke[]) it.next(), seq)) {
409: return LocaleSupport.getString("MSP_Collision"); // NOI18N
410: }
411: }
412: return null; // no colliding sequence
413: }
414:
415: String getCollisionString(KeyStroke[] seq) {
416: if (seq.length == 0)
417: return null; // NOI18N not valid sequence, but don't alert
418: // user
419:
420: Settings.KitAndValue[] kv = Settings.getValueHierarchy(
421: kitClass, SettingsNames.KEY_BINDING_LIST);
422: for (int i = 0; i < kv.length; i++) {
423: Iterator iter = ((List) kv[i].value).iterator();
424: while (iter.hasNext()) {
425: MultiKeyBinding b = (MultiKeyBinding) iter.next();
426: KeyStroke[] ks = b.keys;
427: if (ks == null && b.key != null) {
428: ks = new KeyStroke[1];
429: ks[0] = b.key;
430: }
431: if (ks != null && isOverlapingSequence(ks, seq)) {
432: Object[] values = {
433: Utilities.keySequenceToString(ks),
434: b.actionName };
435: return MessageFormat
436: .format(
437: LocaleSupport
438: .getString("MSP_FMT_Collision"),
439: values); // NOI18N
440: }
441: }
442: }
443: return null; // no colliding sequence
444: }
445:
446: private boolean isOverlapingSequence(KeyStroke[] s1,
447: KeyStroke[] s2) {
448: int l = Math.min(s1.length, s2.length);
449: if (l == 0)
450: return false;
451: while (l-- > 0)
452: if (!s1[l].equals(s2[l]))
453: return false;
454: return true;
455: }
456: }
457:
458: }
|