001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.visualweb.propertyeditors;
042:
043: import com.sun.rave.propertyeditors.domains.Domain;
044: import com.sun.rave.propertyeditors.domains.EditableDomain;
045: import com.sun.rave.propertyeditors.domains.Element;
046:
047: import java.awt.event.KeyEvent;
048: import java.awt.event.KeyListener;
049: import java.text.MessageFormat;
050: import java.util.ResourceBundle;
051: import java.util.Timer;
052: import java.util.TimerTask;
053: import javax.swing.DefaultListModel;
054:
055: import javax.swing.JList;
056: import javax.swing.ListModel;
057: import javax.swing.event.ListSelectionEvent;
058: import javax.swing.event.ListSelectionListener;
059:
060: /**
061: * A custom property editor panel for selecting one element of a domain of
062: * elements. The panel presents the elements in a scrollable listbox, and
063: * emulates the keystroke look-ahead functionality found in MS Windows file
064: * explorer.
065: *
066: * @author gjmurphy
067: */
068: public class SelectOneDomainPanel extends PropertyPanelBase {
069:
070: static ResourceBundle bundle = ResourceBundle
071: .getBundle(SelectOneDomainPanel.class.getPackage()
072: .getName()
073: + ".Bundle"); //NOI18N
074:
075: // The domain from which this panel draws its elements
076: protected Domain domain;
077: // The element selected by the user
078: protected Element element;
079:
080: private DefaultListModel listModel;
081:
082: /**
083: * Creates a new form SelectOneDomainPanel, with elements drawn from the
084: * specified property editor's domain.
085: */
086: public SelectOneDomainPanel(SelectOneDomainEditor propertyEditor) {
087: super (propertyEditor);
088: domain = propertyEditor.getDomain();
089: element = propertyEditor.getElement();
090: assert domain != null;
091: // Populate a list model with domain elements
092: this .listModel = new DefaultListModel();
093: Element[] elements = domain.getElements();
094: for (int i = 0; i < elements.length; i++)
095: listModel.addElement(elements[i].getLabel());
096: // Initialize the user interface
097: initComponents();
098: // Show editing buttons only when domain is editable
099: if (domain instanceof EditableDomain)
100: this .buttonPanel.setVisible(true);
101: else
102: this .buttonPanel.setVisible(false);
103: // If there is a property value already, highlight the element's label
104: // in the list widget
105: if (element != null) {
106: int i = 0;
107: while (i < elements.length) {
108: if (element.equals(elements[i]))
109: break;
110: i++;
111: }
112: if (i < elements.length) {
113: this .domainList.setSelectedIndex(i);
114: this .domainList.ensureIndexIsVisible(i);
115: }
116: }
117: // If no property value already, do not enable edit and delete buttons
118: else {
119: this .editButton.setEnabled(false);
120: this .deleteButton.setEnabled(false);
121: }
122: // Initialize list event listeners
123: ListEventListener eventListener = new ListEventListener(
124: domainList);
125: this .domainList.addListSelectionListener(eventListener);
126: this .domainList.addKeyListener(eventListener);
127: }
128:
129: public Object getPropertyValue() throws IllegalStateException {
130: if (this .element == null)
131: return null;
132: return this .element.getValue();
133: }
134:
135: /**
136: * Called when a new list item has been selected.
137: */
138: public void valueChanged(ListSelectionEvent event) {
139: }
140:
141: /** This method is called from within the constructor to
142: * initialize the form.
143: * WARNING: Do NOT modify this code. The content of this method is
144: * always regenerated by the Form Editor.
145: */
146: // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
147: private void initComponents() {
148: java.awt.GridBagConstraints gridBagConstraints;
149:
150: String domainDisplayName = this .domain.getDisplayName();
151: String listLabelString;
152: if (domainDisplayName == null)
153: listLabelString = bundle
154: .getString("SelectOneDomainPanel.list.label.default");
155: else
156: listLabelString = MessageFormat.format(bundle
157: .getString("SelectOneDomainPanel.list.label"),
158: new String[] { domainDisplayName });
159: listLabel = new javax.swing.JLabel();
160: domainScrollPane = new javax.swing.JScrollPane();
161: domainList = new JList(this .listModel);
162: buttonPanel = new javax.swing.JPanel();
163: newButton = new javax.swing.JButton();
164: editButton = new javax.swing.JButton();
165: deleteButton = new javax.swing.JButton();
166:
167: setLayout(new java.awt.GridBagLayout());
168:
169: listLabel
170: .setDisplayedMnemonic(java.util.ResourceBundle
171: .getBundle(
172: "org/netbeans/modules/visualweb/propertyeditors/Bundle")
173: .getString(
174: "SelectOneDomainPanel.list.label.mnemonic")
175: .charAt(0));
176: listLabel.setLabelFor(domainList);
177: listLabel.setText(listLabelString);
178: gridBagConstraints = new java.awt.GridBagConstraints();
179: gridBagConstraints.gridx = 0;
180: gridBagConstraints.gridy = 0;
181: gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
182: gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
183: gridBagConstraints.weightx = 1.0;
184: gridBagConstraints.insets = new java.awt.Insets(10, 10, 0, 11);
185: add(listLabel, gridBagConstraints);
186:
187: domainList.setMinimumSize(new java.awt.Dimension(64, 64));
188: domainList.setVisibleRowCount(getLabelRowCount());
189: domainScrollPane.setViewportView(domainList);
190: domainList
191: .getAccessibleContext()
192: .setAccessibleName(
193: bundle
194: .getString("SelectOneDomainPanel.list.accessibleName")); // NOI18N
195: domainList
196: .getAccessibleContext()
197: .setAccessibleDescription(
198: bundle
199: .getString("SelectOneDomainPanel.list.accessibleDescription")); // NOI18N
200:
201: gridBagConstraints = new java.awt.GridBagConstraints();
202: gridBagConstraints.gridx = 0;
203: gridBagConstraints.gridy = 1;
204: gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
205: gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
206: gridBagConstraints.weightx = 1.0;
207: gridBagConstraints.weighty = 1.0;
208: gridBagConstraints.insets = new java.awt.Insets(6, 10, 0, 11);
209: add(domainScrollPane, gridBagConstraints);
210:
211: buttonPanel.setLayout(new java.awt.FlowLayout(
212: java.awt.FlowLayout.LEFT, 6, 5));
213:
214: newButton
215: .setMnemonic(java.util.ResourceBundle
216: .getBundle(
217: "org/netbeans/modules/visualweb/propertyeditors/Bundle")
218: .getString(
219: "SelectOneDomainPanel.button.new.mnemonic")
220: .charAt(0));
221: java.util.ResourceBundle bundle = java.util.ResourceBundle
222: .getBundle("org/netbeans/modules/visualweb/propertyeditors/Bundle"); // NOI18N
223: newButton.setText(bundle
224: .getString("SelectOneDomainPanel.button.new")); // NOI18N
225: newButton.setActionCommand("new");
226: newButton
227: .addActionListener(new java.awt.event.ActionListener() {
228: public void actionPerformed(
229: java.awt.event.ActionEvent evt) {
230: handleButtonAction(evt);
231: }
232: });
233: buttonPanel.add(newButton);
234: newButton
235: .getAccessibleContext()
236: .setAccessibleName(
237: bundle
238: .getString("SelectOneDomainPanel.button.new.accessibleName")); // NOI18N
239: newButton
240: .getAccessibleContext()
241: .setAccessibleDescription(
242: bundle
243: .getString("SelectOneDomainPanel.button.new.accessibleDescription")); // NOI18N
244:
245: editButton
246: .setMnemonic(java.util.ResourceBundle
247: .getBundle(
248: "org/netbeans/modules/visualweb/propertyeditors/Bundle")
249: .getString(
250: "SelectOneDomainPanel.button.edit.mnemonic")
251: .charAt(0));
252: editButton.setText(bundle
253: .getString("SelectOneDomainPanel.button.edit")); // NOI18N
254: editButton.setActionCommand("edit");
255: editButton
256: .addActionListener(new java.awt.event.ActionListener() {
257: public void actionPerformed(
258: java.awt.event.ActionEvent evt) {
259: handleButtonAction(evt);
260: }
261: });
262: buttonPanel.add(editButton);
263: editButton
264: .getAccessibleContext()
265: .setAccessibleName(
266: bundle
267: .getString("SelectOneDomainPanel.button.edit.accessibleName")); // NOI18N
268: editButton
269: .getAccessibleContext()
270: .setAccessibleDescription(
271: bundle
272: .getString("SelectOneDomainPanel.button.edit.accessibleDescription")); // NOI18N
273:
274: deleteButton
275: .setMnemonic(java.util.ResourceBundle
276: .getBundle(
277: "org/netbeans/modules/visualweb/propertyeditors/Bundle")
278: .getString(
279: "SelectOneDomainPanel.button.delete.mnemonic")
280: .charAt(0));
281: deleteButton.setText(bundle
282: .getString("SelectOneDomainPanel.button.delete")); // NOI18N
283: deleteButton.setActionCommand("delete");
284: deleteButton
285: .addActionListener(new java.awt.event.ActionListener() {
286: public void actionPerformed(
287: java.awt.event.ActionEvent evt) {
288: handleButtonAction(evt);
289: }
290: });
291: buttonPanel.add(deleteButton);
292: deleteButton
293: .getAccessibleContext()
294: .setAccessibleName(
295: bundle
296: .getString("SelectOneDomainPanel.button.delete.accessibleName")); // NOI18N
297: deleteButton
298: .getAccessibleContext()
299: .setAccessibleDescription(
300: bundle
301: .getString("SelectOneDomainPanel.button.delete.accessibleDescription")); // NOI18N
302:
303: gridBagConstraints = new java.awt.GridBagConstraints();
304: gridBagConstraints.gridx = 0;
305: gridBagConstraints.gridy = 2;
306: gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
307: gridBagConstraints.insets = new java.awt.Insets(4, 5, 0, 0);
308: add(buttonPanel, gridBagConstraints);
309: }// </editor-fold>//GEN-END:initComponents
310:
311: private void handleButtonAction(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_handleButtonAction
312: String action = evt.getActionCommand();
313: EditableDomain editableDomain = (EditableDomain) this .domain;
314: if (action.equals("new")) {
315: Element newElement = (new EditElementDialog(editableDomain))
316: .showDialog(this );
317: if (newElement != null) {
318: editableDomain.addElement(newElement);
319: this .listModel.addElement(newElement.getLabel());
320: this .domainList.setSelectedIndex(editableDomain
321: .getSize() - 1);
322: }
323: } else if (action.equals("edit")) {
324: int index = this .domainList.getSelectedIndex();
325: if (index >= 0 && index < domain.getSize()) {
326: Element element = editableDomain.getElementAt(index);
327: Element newElement = (new EditElementDialog(element,
328: editableDomain)).showDialog(this );
329: if (newElement != null && !(newElement.equals(element))) {
330: editableDomain.setElementAt(index, newElement);
331: this .listModel.set(index, newElement.getLabel());
332: }
333: }
334: } else if (action.equals("delete")) {
335: int index = this .domainList.getSelectedIndex();
336: if (index >= 0 && index < domain.getSize()) {
337: editableDomain.removeElementAt(index);
338: this .listModel.remove(index);
339: if (index == this .listModel.getSize())
340: index--;
341: this .domainList.setSelectedIndex(index);
342: }
343: }
344: }//GEN-LAST:event_handleButtonAction
345:
346: // Variables declaration - do not modify//GEN-BEGIN:variables
347: private javax.swing.JPanel buttonPanel;
348: private javax.swing.JButton deleteButton;
349: private javax.swing.JList domainList;
350: private javax.swing.JScrollPane domainScrollPane;
351: private javax.swing.JButton editButton;
352: private javax.swing.JLabel listLabel;
353: private javax.swing.JButton newButton;
354:
355: // End of variables declaration//GEN-END:variables
356:
357: private int getLabelColumnCount() {
358: int c = 8;
359: Element[] elements = this .domain.getElements();
360: for (int i = 0; i < elements.length; i++) {
361: if (elements[i].getLabel().length() > c)
362: c = elements[i].getLabel().length();
363: }
364: return c;
365: }
366:
367: private int getLabelRowCount() {
368: return this .domain.getSize() < 16 ? this .domain.getSize() : 16;
369: }
370:
371: class ListEventListener implements KeyListener,
372: ListSelectionListener {
373:
374: // Delay in milliseconds before keystroke buffer will be erased
375: static final long BUFFER_ERASE_DELAY = 350;
376:
377: JList list;
378: StringBuffer keyStrokeBuffer;
379: Timer keyStrokeTimer;
380: TimerTask bufferEraseTask;
381:
382: ListEventListener(JList list) {
383: this .list = list;
384: keyStrokeBuffer = new StringBuffer(16);
385: keyStrokeTimer = new Timer();
386: }
387:
388: public void keyTyped(KeyEvent event) {
389: char c = event.getKeyChar();
390: if (!Character.isISOControl(c)) {
391: synchronized (keyStrokeBuffer) {
392: if (bufferEraseTask != null)
393: bufferEraseTask.cancel();
394: keyStrokeBuffer.append(c);
395: bufferEraseTask = new TimerTask() {
396: public void run() {
397: keyStrokeBuffer.setLength(0);
398: }
399: };
400: repositionSelectedItem(keyStrokeBuffer.toString());
401: keyStrokeTimer.schedule(bufferEraseTask,
402: BUFFER_ERASE_DELAY);
403: }
404: }
405: }
406:
407: private void repositionSelectedItem(String prefix) {
408: int i = this .list.getSelectedIndex() - 1;
409: ListModel listModel = this .list.getModel();
410: // If an item is already selected, try to find the next item that
411: // matches the current set of typed keys
412: if (i >= 0) {
413: for (int j = i + 1; j < listModel.getSize(); j++) {
414: if (((String) listModel.getElementAt(j))
415: .regionMatches(true, 0, prefix, 0, prefix
416: .length())) {
417: this .list.setSelectedIndex(j);
418: this .list.ensureIndexIsVisible(j);
419: return;
420: }
421: }
422: }
423: // Either no item was selected, or an item was selected but no
424: // subsequent matching item was found: so, start search for a match
425: // from the beginning of the list.
426: for (int j = 0; j < listModel.getSize(); j++) {
427: if (((String) listModel.getElementAt(j)).regionMatches(
428: true, 0, prefix, 0, prefix.length())) {
429: this .list.setSelectedIndex(j);
430: this .list.ensureIndexIsVisible(j);
431: return;
432: }
433: }
434: // No matchs were found anywhere in the list: leave current selection,
435: // if any, alone.
436: return;
437: }
438:
439: public void keyReleased(KeyEvent event) {
440: }
441:
442: public void keyPressed(KeyEvent event) {
443: }
444:
445: /**
446: * User selected a list item by clicking on it. Set the current element
447: * to be that with the selected label.
448: */
449: public void valueChanged(ListSelectionEvent event) {
450: int index = ((JList) event.getSource()).getSelectedIndex();
451: SelectOneDomainPanel.this .element = SelectOneDomainPanel.this .domain
452: .getElementAt(index);
453: SelectOneDomainPanel.this .editButton.setEnabled(true);
454: SelectOneDomainPanel.this .deleteButton.setEnabled(true);
455: }
456:
457: }
458: }
|