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.faces.dt.binding;
042:
043: import java.awt.Component;
044: import java.awt.FlowLayout;
045: import java.awt.Graphics;
046: import java.awt.GridBagConstraints;
047: import java.awt.GridBagLayout;
048: import java.awt.Image;
049: import java.awt.Insets;
050: import java.awt.event.ActionEvent;
051: import java.awt.event.ActionListener;
052: import java.awt.event.ItemEvent;
053: import java.awt.event.ItemListener;
054: import java.beans.BeanInfo;
055: import java.beans.PropertyDescriptor;
056: import java.util.ArrayList;
057: import java.util.HashMap;
058: import javax.faces.component.UIComponent;
059: import javax.swing.ButtonGroup;
060: import javax.swing.DefaultComboBoxModel;
061: import javax.swing.DefaultListCellRenderer;
062: import javax.swing.DefaultListModel;
063: import javax.swing.Icon;
064: import javax.swing.ImageIcon;
065: import javax.swing.JComboBox;
066: import javax.swing.JLabel;
067: import javax.swing.JList;
068: import javax.swing.JPanel;
069: import javax.swing.JRadioButton;
070: import javax.swing.JScrollPane;
071: import javax.swing.JTextPane;
072: import javax.swing.ListSelectionModel;
073: import javax.swing.UIManager;
074: import javax.swing.event.ListSelectionEvent;
075: import javax.swing.event.ListSelectionListener;
076: import com.sun.rave.designtime.CategoryDescriptor;
077: import com.sun.rave.designtime.Constants;
078: import com.sun.rave.designtime.DesignBean;
079: import com.sun.rave.designtime.DesignContext;
080: import com.sun.rave.designtime.DesignProperty;
081: import com.sun.rave.designtime.markup.AttributeDescriptor;
082: import org.netbeans.modules.visualweb.faces.dt.util.ComponentBundle;
083:
084: public class SourcePanel extends JPanel {
085:
086: private static final ComponentBundle bundle = ComponentBundle
087: .getBundle(SourcePanel.class);
088:
089: JComboBox compCombo = new JComboBox();
090: JLabel compLabel = new JLabel();
091: DefaultComboBoxModel compComboModel = new DefaultComboBoxModel();
092: DefaultListModel propListModel = new DefaultListModel();
093: JLabel propLabel = new JLabel();
094: JScrollPane propScroll = new JScrollPane();
095: JList propList = new JList();
096: JRadioButton showDefault = new JRadioButton();
097: JRadioButton showAdvanced = new JRadioButton();
098: JRadioButton showAll = new JRadioButton();
099: JPanel radioPanel = new JPanel();
100: FlowLayout flowLayout1 = new FlowLayout();
101: GridBagLayout gridBagLayout1 = new GridBagLayout();
102: ButtonGroup showGroup = new ButtonGroup();
103: JTextPane noneText = new JTextPane();
104:
105: public SourcePanel() {
106: try {
107: jbInit();
108: } catch (Exception ex) {
109: // ex.printStackTrace();
110: }
111: }
112:
113: protected BindingPanel bindingPanel;
114:
115: public SourcePanel(BindingPanel bindingPanel) {
116: this ();
117: this .bindingPanel = bindingPanel;
118: }
119:
120: protected DesignContext showingContext = null;
121:
122: public void sourceContextChanged(DesignContext context) {
123: if (showingContext != null && showingContext == context)
124: return;
125: showingContext = context;
126: compComboModel.removeAllElements();
127: if (context != null) {
128: DesignBean root = context.getRootContainer();
129: fillCombo(root.getChildBeans());
130: }
131: }
132:
133: protected DesignBean showingBean = null;
134:
135: public void sourceBeanChanged(DesignBean bean) {
136: if (showingBean == bean)
137: return;
138: showingBean = bean;
139: if (bean != null) {
140: compCombo.setSelectedItem(bean);
141: enumProps();
142: } else {
143: propListModel.removeAllElements();
144: }
145: }
146:
147: protected DesignProperty showingProp = null;
148:
149: public void sourcePropertyChanged(DesignProperty prop) {
150: if (showingProp == prop)
151: return;
152: showingProp = prop;
153: if (prop != null) {
154: propList.setSelectedValue(prop, true);
155: } else {
156: propList.clearSelection();
157: }
158: }
159:
160: protected void fillCombo(DesignBean[] beans) {
161: for (int i = 0; i < beans.length; i++) {
162: if (beans[i].getInstance() instanceof UIComponent) {
163: compComboModel.addElement(beans[i]);
164: }
165: if (beans[i].isContainer()) {
166: fillCombo(beans[i].getChildBeans());
167: }
168: }
169: }
170:
171: protected void enumProps() {
172: DesignProperty[] props = bindingPanel.getSourceBean()
173: .getProperties();
174: propListModel.removeAllElements();
175: ArrayList pa = new ArrayList();
176: for (int i = 0; i < props.length; i++) {
177: // no read-only properties
178: if (props[i].getPropertyDescriptor().getWriteMethod() == null) {
179: continue;
180: }
181: // remove non-bindable properties
182: AttributeDescriptor ad = (AttributeDescriptor) props[i]
183: .getPropertyDescriptor()
184: .getValue(
185: Constants.PropertyDescriptor.ATTRIBUTE_DESCRIPTOR);
186: if (ad == null || !ad.isBindable()) {
187: continue;
188: }
189: // remove hidden/expert props
190: if (showDefault.isSelected()) {
191: CategoryDescriptor pcd = (CategoryDescriptor) props[i]
192: .getPropertyDescriptor().getValue(
193: Constants.PropertyDescriptor.CATEGORY);
194: if (props[i].getPropertyDescriptor().isHidden()
195: || props[i].getPropertyDescriptor().isExpert()
196: || (pcd != null && pcd.getName().equals(
197: "Advanced"))) { // JOE! HACK!
198: continue;
199: }
200: }
201: // remove hidden props
202: else if (showAdvanced.isSelected()) {
203: if (props[i].getPropertyDescriptor().isHidden()) {
204: continue;
205: }
206: }
207: pa.add(props[i]);
208: }
209: ArrayList mods = new ArrayList();
210: ArrayList rest = new ArrayList();
211: for (int i = 0; i < pa.size(); i++) {
212: DesignProperty p = (DesignProperty) pa.get(i);
213: if (p.isModified()) {
214: String vx = p.getValueSource();
215: if (vx != null && vx.startsWith("#{")
216: && vx.endsWith("}")) { //NOI18N
217: mods.add(p);
218: continue;
219: }
220: }
221: rest.add(p);
222: }
223: for (int i = 0; i < mods.size(); i++) {
224: propListModel.addElement(mods.get(i));
225: }
226: for (int i = 0; i < rest.size(); i++) {
227: propListModel.addElement(rest.get(i));
228: }
229: if (propListModel.getSize() > 0) {
230: this .remove(noneText);
231: this .add(propScroll, propScrollConstraints);
232: if (mods.size() > 0) {
233: propList.setSelectedIndex(0);
234: } else {
235: for (int i = 0; i < rest.size(); i++) {
236: if (((DesignProperty) rest.get(i))
237: .getPropertyDescriptor().getName() == "value") { //NOI18N
238: propList.setSelectedValue(rest.get(i), true);
239: break;
240: }
241: }
242: }
243: if (propList.getSelectedValue() == null) {
244: propList.setSelectedIndex(0);
245: }
246: } else {
247: this .remove(propScroll);
248: this .add(noneText, propScrollConstraints);
249: }
250: this .validate();
251: this .doLayout();
252: this .repaint(100);
253: }
254:
255: GridBagConstraints propScrollConstraints = new GridBagConstraints(
256: 0, 3, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER,
257: GridBagConstraints.BOTH, new Insets(0, 8, 0, 0), 0, 0);
258:
259: void jbInit() throws Exception {
260: this .setLayout(gridBagLayout1);
261:
262: noneText.setEditable(false);
263: noneText.setFont(propLabel.getFont());
264: noneText.setBorder(UIManager.getBorder("TextField.border")); //NOI18N
265: noneText.setText(bundle.getMessage("noBindableProps")); //NOI18N
266:
267: compLabel.setText(bundle.getMessage("selectComponent")); //NOI18N
268: compCombo.setModel(compComboModel);
269: compCombo.setRenderer(new CompComboRenderer());
270: compCombo.setEditable(false);
271: compCombo.addActionListener(new ActionListener() {
272: public void actionPerformed(ActionEvent e) {
273: compCombo_actionPerformed(e);
274: }
275: });
276: propLabel.setText(bundle.getMessage("selectBindableProp")); //NOI18N
277: propList.setModel(propListModel);
278: propList.setCellRenderer(new PropListRenderer());
279: propList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
280: propList.getSelectionModel().addListSelectionListener(
281: new ListSelectionListener() {
282: public void valueChanged(ListSelectionEvent e) {
283: propList_valueChanged(e);
284: }
285: });
286: showDefault.setText(bundle.getMessage("default")); //NOI18N
287: showDefault.setSelected(true);
288: showDefault.addItemListener(new ItemListener() {
289: public void itemStateChanged(ItemEvent e) {
290: show_itemStateChanged(e);
291: }
292: });
293: showAdvanced.setText(bundle.getMessage("advanced")); //NOI18N
294: showAdvanced.addItemListener(new ItemListener() {
295: public void itemStateChanged(ItemEvent e) {
296: show_itemStateChanged(e);
297: }
298: });
299: showAll.setText(bundle.getMessage("all")); //NOI18N
300: showAll.addItemListener(new ItemListener() {
301: public void itemStateChanged(ItemEvent e) {
302: show_itemStateChanged(e);
303: }
304: });
305: radioPanel.setLayout(flowLayout1);
306: flowLayout1.setAlignment(FlowLayout.LEFT);
307: flowLayout1.setHgap(5);
308: flowLayout1.setVgap(0);
309: // this.add(compCombo, new GridBagConstraints(0, 1, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER,
310: // GridBagConstraints.HORIZONTAL, new Insets(0, 8, 0, 0), 0, 0));
311: // this.add(compLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST,
312: // GridBagConstraints.HORIZONTAL, new Insets(8, 8, 2, 0), 0, 0));
313: this .add(propLabel, new GridBagConstraints(0, 2, 1, 1, 0.0,
314: 0.0, GridBagConstraints.WEST,
315: GridBagConstraints.HORIZONTAL, new Insets(8, 8, 2, 0),
316: 0, 0));
317: this .add(propScroll, propScrollConstraints);
318: this .add(radioPanel, new GridBagConstraints(0, 4, 1, 1, 1.0,
319: 0.0, GridBagConstraints.CENTER,
320: GridBagConstraints.HORIZONTAL, new Insets(0, 0, 8, 0),
321: 0, 0));
322: radioPanel.add(showDefault, null);
323: radioPanel.add(showAdvanced, null);
324: radioPanel.add(showAll, null);
325: propScroll.getViewport().add(propList, null);
326: showGroup.add(showDefault);
327: showGroup.add(showAdvanced);
328: showGroup.add(showAll);
329: }
330:
331: class CompComboRenderer extends DefaultListCellRenderer {
332: public Component getListCellRendererComponent(JList list,
333: Object value, int index, boolean isSelected,
334: boolean cellHasFocus) {
335: super .getListCellRendererComponent(list, value, index,
336: isSelected, cellHasFocus);
337:
338: if (value instanceof DesignBean) {
339: DesignBean b = (DesignBean) value;
340:
341: String prefix = ""; //NOI18N
342: DesignBean p = b.getBeanParent();
343: while (p != null
344: && p != b.getDesignContext().getRootContainer()) {
345: prefix += " "; //NOI18N
346: p = p.getBeanParent();
347: }
348:
349: this .setText(prefix + b.getInstanceName());
350: BeanInfo bi = b.getBeanInfo();
351: Image img = bi.getIcon(BeanInfo.ICON_COLOR_16x16);
352: if (img != null) {
353: this .setIcon(new ImageIcon(img));
354: } else {
355: this .setIcon(BEAN_ICON);
356: }
357: }
358:
359: return this ;
360: }
361: }
362:
363: protected static Icon BLANK_ICON = new Icon() {
364: public void paintIcon(Component c, Graphics g, int x, int y) {
365: g.setColor(c.getBackground());
366: g.fillRect(x, y, 16, 16);
367: }
368:
369: public int getIconWidth() {
370: return 16;
371: }
372:
373: public int getIconHeight() {
374: return 16;
375: }
376: };
377:
378: protected static Icon BEAN_ICON = new ImageIcon(SourcePanel.class
379: .getResource("bean.gif")); //NOI18N
380:
381: class PropListRenderer extends DefaultListCellRenderer {
382: public Component getListCellRendererComponent(JList list,
383: Object value, int index, boolean isSelected,
384: boolean cellHasFocus) {
385: super .getListCellRendererComponent(list, value, index,
386: isSelected, cellHasFocus);
387:
388: if (value instanceof DesignProperty) {
389: DesignProperty p = (DesignProperty) value;
390:
391: PropertyDescriptor pd = p.getPropertyDescriptor();
392: String cn = pd.getPropertyType().getName();
393: if (cn.startsWith("[")) { //NOI18N
394: cn = decodeTypeName(cn);
395: }
396: if (cn.indexOf(".") > -1) { //NOI18N
397: cn = cn.substring(cn.lastIndexOf(".") + 1); //NOI18N
398: }
399:
400: boolean bold = false;
401: if (p.isModified()) {
402: String vx = p.getValueSource();
403: if (vx == null) {
404: vx = "";
405: }
406: bold = vx.startsWith("#{") && vx.endsWith("}"); //NOI18N
407: }
408:
409: StringBuffer sb = new StringBuffer();
410: sb.append("<html>"); //NOI18N
411: if (bold) {
412: sb.append("<b>"); //NOI18N
413: }
414: sb.append(pd.getName());
415: if (bold) {
416: sb.append("</b>"); //NOI18N
417: }
418: sb.append(" <font size=\"-1\"><i>"); //NOI18N
419: sb.append(cn);
420: sb.append("</i></font></html>"); //NOI18N
421: this .setText(sb.toString());
422: this .setIcon(UIManager.getIcon("Tree.leafIcon")); //NOI18N
423: }
424:
425: return this ;
426: }
427: }
428:
429: void show_itemStateChanged(ItemEvent e) {
430: Object o = propList.getSelectedValue();
431: enumProps();
432: propList.setSelectedValue(o, false);
433: }
434:
435: void compCombo_actionPerformed(ActionEvent e) {
436: DesignBean b = (DesignBean) compCombo.getSelectedItem();
437: bindingPanel.setSourceBean(b);
438: }
439:
440: void propList_valueChanged(ListSelectionEvent e) {
441: DesignProperty p = (DesignProperty) propList.getSelectedValue();
442: bindingPanel.setSourceProperty(p);
443: }
444:
445: static HashMap arrayTypeKeyHash = new HashMap();
446: static {
447: arrayTypeKeyHash.put("B", "byte"); //NOI18N
448: arrayTypeKeyHash.put("C", "char"); //NOI18N
449: arrayTypeKeyHash.put("D", "double"); //NOI18N
450: arrayTypeKeyHash.put("F", "float"); //NOI18N
451: arrayTypeKeyHash.put("I", "int"); //NOI18N
452: arrayTypeKeyHash.put("J", "long"); //NOI18N
453: arrayTypeKeyHash.put("S", "short"); //NOI18N
454: arrayTypeKeyHash.put("Z", "boolean"); //NOI18N
455: arrayTypeKeyHash.put("V", "void"); //NOI18N
456: }
457:
458: String decodeTypeName(String tn) {
459: if (tn.startsWith("[")) { //NOI18N
460: int depth = 0;
461: while (tn.startsWith("[")) { //NOI18N
462: tn = tn.substring(1);
463: depth++;
464: }
465: if (tn.startsWith("L")) { //NOI18N
466: tn = tn.substring(1);
467: tn = tn.substring(0, tn.length() - 1);
468: } else {
469: char typeKey = tn.charAt(0);
470: tn = (String) arrayTypeKeyHash.get("" + typeKey); //NOI18N
471: }
472: for (int i = 0; i < depth; i++) {
473: tn += "[]"; //NOI18N
474: }
475: }
476: return tn;
477: }
478: }
|