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.binding.data;
042:
043: import java.awt.event.ActionEvent;
044: import java.awt.event.ActionListener;
045: import java.awt.event.ComponentAdapter;
046: import java.awt.event.ComponentEvent;
047: import java.util.ArrayList;
048: import java.util.HashMap;
049: import java.util.Iterator;
050: import java.util.List;
051: import java.util.StringTokenizer;
052: import java.awt.Component;
053: import java.awt.Dimension;
054: import java.awt.GridBagConstraints;
055: import java.awt.GridBagLayout;
056: import java.awt.Insets;
057: import java.awt.event.ItemEvent;
058: import java.awt.event.ItemListener;
059: import javax.swing.DefaultListCellRenderer;
060: import javax.swing.DefaultListModel;
061: import javax.swing.JButton;
062: import javax.swing.JComboBox;
063: import javax.swing.JLabel;
064: import javax.swing.JList;
065: import javax.swing.JScrollPane;
066: import javax.swing.JTextPane;
067: import javax.swing.ListModel;
068: import javax.swing.SwingUtilities;
069: import javax.swing.UIManager;
070: import javax.swing.event.ListSelectionEvent;
071: import javax.swing.event.ListSelectionListener;
072: import com.sun.data.provider.DataProvider;
073: import com.sun.data.provider.FieldKey;
074: import com.sun.rave.designtime.Constants;
075: import com.sun.rave.designtime.DesignBean;
076: import com.sun.rave.designtime.DesignContext;
077: import com.sun.rave.designtime.DesignProperty;
078: import com.sun.rave.designtime.faces.FacesDesignContext;
079: import com.sun.rave.designtime.event.DesignContextListener;
080: import com.sun.rave.designtime.Position;
081: import com.sun.rave.designtime.DesignEvent;
082: import com.sun.rave.designtime.DesignProject;
083: import com.sun.rave.designtime.faces.FacesDesignProject;
084: import org.netbeans.modules.visualweb.propertyeditors.binding.BindingTargetCallback;
085: import org.netbeans.modules.visualweb.propertyeditors.binding.PropertyBindingHelper;
086: import org.netbeans.modules.visualweb.propertyeditors.util.Bundle;
087: import org.openide.ErrorManager;
088:
089: // Modified to support Add Data Provider from this panel- Winston
090: // XXX Lots of duplication between BindOptionsToDataProviderPanel & BindValueToDataProviderPanel
091: // Needs clean up
092:
093: /*
094: * @authors
095: * Winston Prakash (cleaned up lots of mess)
096: */
097:
098: public class BindValueToDataProviderPanel extends DataBindingPanel
099: implements DesignContextListener {
100:
101: private static final Bundle bundle = Bundle
102: .getBundle(BindValueToDataProviderPanel.class);
103:
104: protected JTextPane noneText = new JTextPane();
105:
106: protected JLabel dpLabel = new JLabel();
107: protected JComboBox dpCombo = new JComboBox();
108:
109: protected HashMap listModelHash = new HashMap();
110: protected HashMap valSelectedItemHash = new HashMap();
111:
112: protected JLabel valueListLabel = new JLabel();
113: protected JList fieldList = new JList();
114: protected JScrollPane valueListScroll = new JScrollPane(fieldList);
115:
116: protected GridBagLayout gridbag = new GridBagLayout();
117: protected String parentName = null;
118:
119: protected boolean initializing = true;
120:
121: private JButton addDataProviderButton = new JButton();
122:
123: DesignContext[] contexts;
124:
125: private List brokenDataProvider = new ArrayList();
126:
127: DesignProperty designProperty;
128:
129: DesignBean selectedBean = null;
130:
131: protected ListItem val_none = new ListItem();
132:
133: private String newExpression = null;
134:
135: protected class ListItem {
136: public String display;
137: public FieldKey field;
138: public String type;
139:
140: public String toString() {
141: return field != null ? "<html><b>" + field.getDisplayName()
142: + "</b> <i>" + type + "</i></html>"
143: // ? field.getDisplayName() + " (" + type + ")"
144: : display;
145: }
146: }
147:
148: // // scans parent hierarchy for a specific bean type
149: // protected DesignBean scanForParent(Class beanClass, DesignBean child) {
150: // DesignBean parent = child.getBeanParent();
151: // if (parent != null && parent.getInstance() != null) {
152: // if (beanClass.isAssignableFrom(parent.getInstance().getClass())) {
153: // return parent;
154: // }
155: // return scanForParent(beanClass, parent);
156: // }
157: // return null;
158: // }
159:
160: boolean stopDataProviderThread = false;
161:
162: public BindValueToDataProviderPanel(BindingTargetCallback callback,
163: DesignProperty prop) {
164: super (callback, prop);
165: try {
166: jbInit();
167: } catch (Exception e) {
168: e.printStackTrace();
169: }
170:
171: // For Shortfin we removed the Server Navigator window.
172: // Add Data provider dialogs depends on it. So hide it for Shortfin - Winston
173: addDataProviderButton.setVisible(false);
174:
175: dpLabel.setLabelFor(dpCombo);
176: dpCombo.getAccessibleContext().setAccessibleName(
177: bundle.getMessage("DP_COMBO_ACCESS_NAME"));
178: dpCombo.getAccessibleContext().setAccessibleDescription(
179: bundle.getMessage("DP_COMBO_ACCESS_DESC"));
180: addDataProviderButton.getAccessibleContext().setAccessibleName(
181: bundle.getMessage("ADD_DP_BUTTON_ACCESS_NAME"));
182: valueListLabel.setLabelFor(fieldList);
183: fieldList.getAccessibleContext().setAccessibleName(
184: bundle.getMessage("FIELD_LIST_ACCESS_NAME"));
185: fieldList.getAccessibleContext().setAccessibleDescription(
186: bundle.getMessage("FIELD_LIST_ACCESS_DESC"));
187: addDataProviderButton.setMnemonic(bundle.getMessage(
188: "ADD_DP_BUTTON_MNEMONIC").charAt(0));
189: designProperty = prop;
190: dpCombo.addItem(bundle.getMessage("dpRetrievingMessage"));
191: val_none.display = bundle.getMessage("noneBrackets"); //NOI18N
192: Thread dataProvideNodeThread = new Thread(new Runnable() {
193: public void run() {
194: updateDataProvider(designProperty);
195: }
196: });
197: dataProvideNodeThread.setPriority(Thread.MIN_PRIORITY);
198: dataProvideNodeThread.start();
199: addComponentListener(new ComponentAdapter() {
200:
201: public void componentShown(ComponentEvent e) {
202: if (newExpression != null) {
203: if ((newExpression != null) && isShowing()) {
204: bindingCallback
205: .setNewExpressionText(newExpression);
206: }
207: }
208: }
209: });
210: }
211:
212: // For performance improvement. No need to get all the contexts in the project
213: private DesignContext[] getDesignContexts(DesignBean designBean) {
214: DesignProject designProject = designBean.getDesignContext()
215: .getProject();
216: DesignContext[] contexts;
217: if (designProject instanceof FacesDesignProject) {
218: contexts = ((FacesDesignProject) designProject)
219: .findDesignContexts(new String[] { "request",
220: "session", "application" });
221: } else {
222: contexts = new DesignContext[0];
223: }
224: DesignContext[] designContexts = new DesignContext[contexts.length + 1];
225: designContexts[0] = designBean.getDesignContext();
226: System.arraycopy(contexts, 0, designContexts, 1,
227: contexts.length);
228: return designContexts;
229: }
230:
231: protected void updateDataProvider(DesignProperty prop) {
232: if (prop != null) {
233: //contexts = prop.getDesignBean().getDesignContext().getProject().getDesignContexts();
234: contexts = getDesignContexts(prop.getDesignBean());
235:
236: dpLabel.setText(bundle.getMessage("chooseDpToBind", prop
237: .getDesignBean().getInstanceName())); //NOI18N
238:
239: // // first check to see if the comp is in a UIData bound to a RowSet
240: // DesignBean tableBean = scanForParent(UIData.class, prop.getDesignBean());
241: // if (tableBean != null) {
242: // //!JOE do this later...
243: // }
244:
245: // find the current value
246: String currentRef = prop.getValueSource();
247: String contextName = null;
248: String dpName = null;
249: String valueField = null;
250: // "#{Page1.personDataProvider['NAME']}"
251: if (currentRef != null && currentRef.startsWith("#{") && //NOI18N
252: currentRef.endsWith("}")) { //NOI18N
253:
254: ArrayList parts = new ArrayList();
255: StringTokenizer st = new StringTokenizer(currentRef
256: .substring(2, currentRef.length() - 1), ".[");
257: while (st.hasMoreElements()) {
258: parts.add(st.nextElement());
259: }
260:
261: if (parts.size() > 0) {
262: contextName = "" + parts.get(0);
263: }
264: if (parts.size() > 1) {
265: dpName = "" + parts.get(1);
266: }
267: /*if (parts.size() > 2) {
268: String val = String.valueOf(parts.get(2));
269: if (val.startsWith("'") && val.endsWith("']")) { //NOI18N
270: valueField = val.substring(1, val.length() - 2); //NOI18N
271: }
272: }*/
273:
274: //XXX - revisit after EA - WInston
275: int startIndex = currentRef.indexOf('[');
276: int endIndex = currentRef.indexOf(']');
277: if ((startIndex != -1) && (endIndex != -1)) {
278: valueField = currentRef.substring(startIndex + 2,
279: endIndex - 1);
280: }
281: /*System.out.println("-----------------------------------");
282: System.out.println("-- " + contextName);
283: System.out.println("-- " + dpName);
284: System.out.println("-- " + valueField);
285: System.out.println("-----------------------------------");*/
286: }
287:
288: // then scan for all dataproviders
289: ArrayList dpBeans = new ArrayList();
290: for (int i = 0; i < contexts.length; i++) {
291: String scope = (String) contexts[i]
292: .getContextData(Constants.ContextData.SCOPE);
293: if ("request".equals(scope)
294: && contexts[i] != prop.getDesignBean()
295: .getDesignContext()) { //NOI18N
296: continue;
297: }
298: DesignBean[] dpbs = contexts[i]
299: .getBeansOfType(DataProvider.class);
300: for (int j = 0; j < dpbs.length; j++) {
301: dpBeans.add(dpbs[j]);
302: }
303: }
304:
305: if (dpBeans.size() > 0) {
306: for (int i = 0; i < dpBeans.size(); i++) {
307: if (stopDataProviderThread)
308: return;
309: DesignBean dpBean = (DesignBean) dpBeans.get(i);
310: DataProvider dp = (DataProvider) dpBean
311: .getInstance();
312: if (dp != null) {
313: if (selectedBean == null) {
314: DesignContext dpc = dpBean
315: .getDesignContext();
316: if (dpc instanceof FacesDesignContext) {
317: if (((FacesDesignContext) dpc)
318: .getReferenceName().equals(
319: contextName)
320: && dpBean.getInstanceName()
321: .equals(dpName)) {
322: selectedBean = dpBean;
323: }
324: } else {
325: if (dpc.getDisplayName().equals(
326: contextName)
327: && dpBean.getInstanceName()
328: .equals(dpName)) {
329: selectedBean = dpBean;
330: }
331: }
332: }
333:
334: DefaultListModel dlm = new DefaultListModel();
335: dlm.addElement(val_none);
336:
337: try {
338: FieldKey[] fields = dp.getFieldKeys();
339: for (int f = 0; f < fields.length; f++) {
340: ListItem li = new ListItem();
341: li.field = fields[f];
342: if ((dp.getType(fields[f]) != null)
343: && dp
344: .getType(fields[f])
345: .toString()
346: .indexOf(
347: "java.lang.Class") == -1) {
348: li.type = PropertyBindingHelper
349: .getPrettyTypeName(dp
350: .getType(fields[f])
351: .getName());
352: dlm.addElement(li);
353: if (dpBean == selectedBean) {
354: String liColumnEscapeApos = li.field
355: .getFieldId()
356: .replaceAll("\\'",
357: "\\\\'"); //NOI18N
358: if (!valSelectedItemHash
359: .containsKey(dpBean)
360: && liColumnEscapeApos
361: .equals(valueField)) {
362: valSelectedItemHash.put(
363: dpBean, li);
364: }
365: }
366: }
367: }
368: } catch (Exception exc) {
369: ErrorManager.getDefault().notify(exc);
370: brokenDataProvider.add(dpBean);
371: }
372: if (!valSelectedItemHash.containsKey(dpBean)) {
373: valSelectedItemHash.put(dpBean, val_none);
374: }
375: listModelHash.put(dpBean, dlm);
376: }
377: }
378: }
379: }
380:
381: SwingUtilities.invokeLater(new Runnable() {
382: public void run() {
383: dpCombo.removeAllItems();
384: Iterator iter = listModelHash.keySet().iterator();
385: while (iter.hasNext()) {
386: dpCombo.addItem(iter.next());
387: }
388: attachListeners();
389: if (dpCombo.getItemCount() > 0) {
390: if (selectedBean != null) {
391: dpCombo.setSelectedItem(selectedBean);
392: updateLists();
393: } else {
394: dpCombo.setSelectedIndex(0);
395: fieldList.setModel((ListModel) listModelHash
396: .get(dpCombo.getSelectedItem()));
397: }
398: }
399: repaint(100);
400: }
401: });
402: }
403:
404: public void addNotify() {
405: super .addNotify();
406: //contexts = designProperty.getDesignBean().getDesignContext().getProject().getDesignContexts();
407: contexts = getDesignContexts(designProperty.getDesignBean());
408: for (int i = 0; i < contexts.length; i++) {
409: //System.out.println("Adding context Listeners - " + contexts[i].getDisplayName());
410: contexts[i]
411: .addDesignContextListener(BindValueToDataProviderPanel.this );
412: }
413: }
414:
415: public void removeNotify() {
416: //contexts = designProperty.getDesignBean().getDesignContext().getProject().getDesignContexts();
417: contexts = getDesignContexts(designProperty.getDesignBean());
418: // Make sure the added listeners to contexts are removed
419: // Sigh! if only design time provide a neater way to clean up.
420: for (int i = 0; i < contexts.length; i++) {
421: //System.out.println("Removing context Listeners - " + contexts[i].getDisplayName());
422: contexts[i].removeDesignContextListener(this );
423: }
424: stopDataProviderThread = true;
425: super .removeNotify();
426: }
427:
428: private void jbInit() throws Exception {
429: noneText.setEditable(false);
430: noneText.setFont(dpLabel.getFont());
431: noneText.setBorder(UIManager.getBorder("TextField.border")); //NOI18N
432: noneText.setText(bundle.getMessage("noDps")); //NOI18N
433:
434: dpLabel.setText(bundle.getMessage("chooseDpToBindSimple")); //NOI18N
435: dpLabel.setDisplayedMnemonic(bundle.getMessage(
436: "chooseDpToBindSimpleDisplayedMnemonic").charAt(0)); //NOI18N
437: valueListLabel.setText(bundle.getMessage("dataField")); //NOI18N
438: valueListLabel.setDisplayedMnemonic(bundle.getMessage(
439: "dataFieldDisplayedMnemonic").charAt(0)); //NOI18N
440: valueListScroll.setPreferredSize(new Dimension(200, 200));
441:
442: dpCombo.setRenderer(new DPComboRenderer());
443:
444: this .setPreferredSize(new Dimension(400, 200));
445: this .setLayout(gridbag);
446:
447: addDataProviderButton.setText(bundle
448: .getMessage("ADD_DP_BUTTON_LBL"));
449: addDataProviderButton.addActionListener(new ActionListener() {
450: public void actionPerformed(ActionEvent evt) {
451: new AddDataProviderDialog().showDialog();
452: }
453: });
454:
455: this .add(dpLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0,
456: GridBagConstraints.WEST, GridBagConstraints.NONE,
457: new Insets(8, 8, 2, 8), 0, 0));
458: this .add(dpCombo, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0,
459: GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
460: new Insets(0, 8, 8, 8), 0, 0));
461: this .add(addDataProviderButton, new GridBagConstraints(1, 1, 1,
462: 1, 1.0, 0.0, GridBagConstraints.WEST,
463: GridBagConstraints.HORIZONTAL, new Insets(0, 8, 8, 8),
464: 0, 0));
465:
466: this .add(valueListLabel, new GridBagConstraints(0, 2, 2, 1,
467: 0.0, 0.0, GridBagConstraints.WEST,
468: GridBagConstraints.NONE, new Insets(0, 8, 2, 8), 0, 0));
469: this .add(valueListScroll, new GridBagConstraints(0, 3, 2, 1,
470: 1.0, 1.0, GridBagConstraints.CENTER,
471: GridBagConstraints.BOTH, new Insets(0, 8, 8, 8), 0, 0));
472:
473: }
474:
475: /**
476: * Private method to attach listeners to Data provider combobox and
477: * value list items after initlaizing the data providers
478: */
479: private void attachListeners() {
480: dpCombo.addItemListener(new ItemListener() {
481: public void itemStateChanged(ItemEvent e) {
482: if (e.getStateChange() == e.SELECTED) {
483: updateLists();
484: }
485: }
486: });
487: fieldList.addListSelectionListener(new ListSelectionListener() {
488: public void valueChanged(ListSelectionEvent e) {
489: if (!e.getValueIsAdjusting()) {
490: updateSelection();
491: }
492: }
493: });
494: }
495:
496: public String getDataBindingTitle() {
497: return bundle.getMessage("bindToDp"); // NOI18N
498: }
499:
500: protected void updateLists() {
501: ListModel vlm = (ListModel) listModelHash.get(dpCombo
502: .getSelectedItem());
503: fieldList.setModel(vlm);
504: fieldList.setSelectedValue(valSelectedItemHash.get(dpCombo
505: .getSelectedItem()), true);
506: }
507:
508: protected void updateSelection() {
509: FieldKey valField = null;
510: ListItem valItem = (ListItem) fieldList.getSelectedValue();
511: if (valItem != null) {
512: valField = valItem.field;
513: }
514: if (valField != null) {
515: newExpression = calcValueRef((DesignBean) dpCombo
516: .getSelectedItem(), valField.getFieldId());
517:
518: if ((newExpression != null) && isShowing()) {
519: bindingCallback.setNewExpressionText(newExpression);
520: }
521: }
522: }
523:
524: protected String calcValueRef(DesignBean dpBean, String fieldId) {
525: if (dpBean == null || fieldId == null || fieldId.length() == 0) {
526: //return ""; //NOI18N
527: return null;
528: }
529: DesignContext c = dpBean.getDesignContext();
530: if (c instanceof FacesDesignContext) {
531: return "#{" + ((FacesDesignContext) c).getReferenceName()
532: + "." + dpBean.getInstanceName() + ".value['"
533: + fieldId + "']}"; //NOI18N
534: }
535: return "#{" + c.getDisplayName() + "."
536: + dpBean.getInstanceName() + ".value['" + fieldId
537: + "']}"; //NOI18N
538: }
539:
540: class DPComboRenderer extends DefaultListCellRenderer {
541: public Component getListCellRendererComponent(JList list,
542: Object value, int index, boolean isSelected,
543: boolean cellHasFocus) {
544: super .getListCellRendererComponent(list, value, index,
545: isSelected, cellHasFocus);
546: if (value instanceof DesignBean) {
547: DesignBean dpBean = (DesignBean) value;
548: if (dpBean != null) {
549: if (brokenDataProvider.contains(dpBean)) {
550: setText(bundle.getMessage(
551: "dpErrorDisplayTextPattern", dpBean
552: .getInstanceName(), dpBean
553: .getDesignContext()
554: .getDisplayName())); //NOI18N
555: } else {
556: setText(bundle.getMessage(
557: "dpDisplayTextPattern", dpBean
558: .getInstanceName(), dpBean
559: .getDesignContext()
560: .getDisplayName())); //NOI18N
561: }
562: }
563: } else if (value instanceof String) {
564: setText((String) value);
565: }
566: return this ;
567: }
568: }
569:
570: // Implementation of DesignContextListener
571:
572: public void beanCreated(DesignBean designBean) {
573: if (designBean.getInstance() instanceof DataProvider) {
574: //System.out.println("Bean Created - " + designBean.getInstanceName());
575: }
576: }
577:
578: public void instanceNameChanged(DesignBean designBean,
579: String oldInstanceName) {
580: if (designBean.getInstance() instanceof DataProvider) {
581: //System.out.println("Instance Name changed - " + oldInstanceName + " to " + designBean.getInstanceName());
582: dpCombo.repaint();
583: }
584: }
585:
586: public void propertyChanged(DesignProperty prop, Object oldValue) {
587: if ((prop.getDesignBean().getInstance() instanceof DataProvider)) {
588: //System.out.println("Bean property Changed - " + prop.getDesignBean().getInstanceName());
589: //System.out.println("Property Name - " + prop.getPropertyDescriptor().getDisplayName());
590: if (prop.getPropertyDescriptor().getName().equals(
591: "CachedRowSet")) {
592: DataProvider dp = (DataProvider) prop.getDesignBean()
593: .getInstance();
594: if (dp != null) {
595: DefaultListModel dlm = new DefaultListModel();
596: dlm.addElement(val_none);
597:
598: listModelHash.put(prop.getDesignBean(), dlm);
599: try {
600: FieldKey[] fields = dp.getFieldKeys();
601: for (int f = 0; f < fields.length; f++) {
602: ListItem li = new ListItem();
603: li.field = fields[f];
604: li.type = PropertyBindingHelper
605: .getPrettyTypeName(dp.getType(
606: fields[f]).getName());
607: dlm.addElement(li);
608: }
609: } catch (Exception exc) {
610: ErrorManager.getDefault().notify(exc);
611: }
612: dpCombo.addItem(prop.getDesignBean());
613: dpCombo.setSelectedItem(prop.getDesignBean());
614: }
615: }
616: }
617: }
618:
619: public void beanChanged(DesignBean designBean) {
620: }
621:
622: public void contextActivated(DesignContext context) {
623: }
624:
625: public void contextDeactivated(DesignContext context) {
626: }
627:
628: public void contextChanged(DesignContext context) {
629: }
630:
631: public void beanDeleted(DesignBean designBean) {
632: }
633:
634: public void beanMoved(DesignBean designBean, DesignBean oldParent,
635: Position pos) {
636: }
637:
638: public void beanContextActivated(DesignBean designBean) {
639: }
640:
641: public void beanContextDeactivated(DesignBean designBean) {
642: }
643:
644: public void eventChanged(DesignEvent event) {
645: }
646: }
|