001: /*
002: * The contents of this file are subject to the terms of the Common Development
003: * and Distribution License (the License). You may not use this file except in
004: * compliance with the License.
005: *
006: * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
007: * or http://www.netbeans.org/cddl.txt.
008: *
009: * When distributing Covered Code, include this CDDL Header Notice in each file
010: * and include the License file at http://www.netbeans.org/cddl.txt.
011: * If applicable, add the following below the CDDL Header, with the fields
012: * enclosed by brackets [] replaced by your own identifying information:
013: * "Portions Copyrighted [year] [name of copyright owner]"
014: *
015: * The Original Software is NetBeans. The Initial Developer of the Original
016: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
017: * Microsystems, Inc. All Rights Reserved.
018: */
019: package org.netbeans.modules.xslt.mapper.xpatheditor;
020:
021: import java.awt.event.ActionEvent;
022: import java.awt.event.ActionListener;
023: import java.awt.event.MouseAdapter;
024: import java.awt.event.MouseEvent;
025: import javax.swing.JPanel;
026: import javax.swing.tree.TreeModel;
027: import javax.swing.tree.TreePath;
028: import org.netbeans.modules.soa.mapper.common.basicmapper.IBasicMapper;
029: import org.netbeans.modules.soa.ui.ExtendedLookup;
030: import org.netbeans.modules.soa.ui.SoaUiUtil;
031: import org.netbeans.modules.soa.ui.axinodes.AxiomChildren;
032: import org.netbeans.modules.soa.ui.axinodes.AxiomNode;
033: import org.netbeans.modules.soa.ui.UserNotification;
034: import org.netbeans.modules.soa.ui.axinodes.NodeType;
035: import org.netbeans.modules.soa.ui.form.ChooserLifeCycle;
036: import org.netbeans.modules.soa.ui.form.valid.Validator;
037: import org.netbeans.modules.soa.ui.nodes.NodeFactory;
038: import org.netbeans.modules.xml.axi.AXIComponent;
039: import org.netbeans.modules.xml.axi.Element;
040: import org.netbeans.modules.xml.xpath.AbstractXPathModelHelper;
041: import org.netbeans.modules.xml.xpath.XPathException;
042: import org.netbeans.modules.xml.xpath.XPathExpression;
043: import org.netbeans.modules.xml.xpath.XPathModel;
044: import org.netbeans.modules.soa.ui.axinodes.AxiomTreeNodeFactory;
045: import org.netbeans.modules.soa.ui.axinodes.AxiomUtils;
046: import org.netbeans.modules.soa.ui.form.valid.DefaultValidator;
047: import org.netbeans.modules.soa.ui.nodes.NodesTreeModel;
048: import org.netbeans.modules.soa.ui.nodes.NodesTreeRenderer;
049: import org.netbeans.modules.xml.xam.dom.AbstractDocumentComponent;
050: import org.netbeans.modules.xslt.mapper.methoid.Constants;
051: import org.netbeans.modules.xslt.mapper.model.MapperContext;
052: import org.netbeans.modules.xslt.mapper.view.XsltMapper;
053: import org.netbeans.modules.xslt.model.XslModel;
054: import org.openide.filesystems.FileObject;
055: import org.openide.filesystems.FileSystem;
056: import org.openide.filesystems.Repository;
057: import org.openide.nodes.Children;
058: import org.openide.nodes.Node;
059: import org.openide.util.Lookup;
060: import org.openide.util.NbBundle;
061:
062: /**
063: *
064: * @author nk160297
065: */
066: public class ExpressionEditor extends JPanel implements
067: ChooserLifeCycle<String>, Validator.Provider {
068: private static final long serialVersionUID = 1L;
069:
070: private XsltMapper myMapper;
071: private DefaultValidator myValidator;
072:
073: private final static String INPUT_PARAM = "InputParam";
074:
075: public ExpressionEditor(IBasicMapper basicMapper) {
076: assert basicMapper instanceof XsltMapper;
077: myMapper = (XsltMapper) basicMapper;
078: createContent();
079: initControls();
080: }
081:
082: public void createContent() {
083: initComponents();
084: Lookup lookup = myMapper.getLookup();
085: //
086: MapperContext context = myMapper.getContext();
087: AXIComponent sourceAxiComponent = context.getSourceType();
088: // if (sourceAxiComponent == null) {
089: // sourceAxiComponent = SourceTreeModel.constructFakeComponent();
090: // }
091: if (sourceAxiComponent != null) {
092: AxiomTreeNodeFactory nodeFactory = new AxiomTreeNodeFactory();
093: Lookup axiLookup = ExtendedLookup.createExtendedLookup(
094: lookup, nodeFactory);
095: Node rootNode;
096: boolean shouldRootBeVisible;
097: if (sourceAxiComponent instanceof Element) {
098: rootNode = nodeFactory.createNode(NodeType.ELEMENT,
099: sourceAxiComponent, axiLookup);
100: shouldRootBeVisible = true;
101: } else {
102: Children children = new AxiomChildren(
103: sourceAxiComponent, axiLookup);
104: String rootNodeName = NbBundle.getMessage(this
105: .getClass(), "LBL_SourceSchemaModel"); // NOI18N
106: rootNode = new NodeFactory.TextNode(children,
107: rootNodeName);
108: shouldRootBeVisible = false;
109: }
110: //
111: TreeModel variablesModel = new NodesTreeModel(rootNode);
112: treeSchema.setModel(variablesModel);
113: treeSchema.setCellRenderer(new NodesTreeRenderer());
114: treeSchema.setRootVisible(shouldRootBeVisible);
115: treeSchema.setShowsRootHandles(true);
116: }
117: //
118: FileObject paletteRootFo = getPaletteFolder(Constants.XSLT_PALETTE_FOLDER);
119: PaletteTreeNodeFactory factory = new PaletteTreeNodeFactory();
120: Lookup paletteLookup = ExtendedLookup.createExtendedLookup(
121: lookup, factory);
122: Node paletteRootNode = factory.createNode(
123: PaletteTreeNodeFactory.NodeType.ROOT, paletteRootFo,
124: paletteLookup);
125: TreeModel functionsModel = new NodesTreeModel(paletteRootNode);
126: //
127: treeFunctions.setModel(functionsModel);
128: treeFunctions.setCellRenderer(new NodesTreeRenderer());
129: treeFunctions.setRootVisible(false);
130: treeFunctions.setShowsRootHandles(true);
131: //
132: treeSchema.addMouseListener(new MouseAdapter() {
133: @Override
134: public void mouseClicked(MouseEvent e) {
135: if (e.getClickCount() == 2 /**&& e.isAltDown() */
136: ) {
137: TreePath tp = treeSchema.getSelectionPath();
138: // TreePath tp = treeSchema.getPathForLocation(e.getX(), e.getY());
139: if (tp != null) {
140: Object lastPathComp = tp.getLastPathComponent();
141: if (lastPathComp != null
142: && lastPathComp instanceof AxiomNode) {
143: addXPath((AxiomNode) lastPathComp);
144: }
145: }
146: }
147: }
148: });
149: //
150: treeFunctions.addMouseListener(new MouseAdapter() {
151: @Override
152: public void mouseClicked(MouseEvent e) {
153: if (e.getClickCount() == 2) {
154: TreePath tp = treeFunctions.getSelectionPath();
155: // TreePath tp = treeFunctions.getPathForLocation(e.getX(), e.getY());
156: if (tp != null) {
157: Object lastPathComp = tp.getLastPathComponent();
158: if (lastPathComp != null
159: && lastPathComp instanceof ItemNode) {
160: addFunction((ItemNode) lastPathComp);
161: }
162: }
163: }
164: }
165: });
166: //
167: btnCheckSyntax.addActionListener(new ActionListener() {
168: public void actionPerformed(ActionEvent e) {
169: boolean isOk = checkSyntax();
170: if (isOk) {
171: String msg = NbBundle.getMessage(
172: ExpressionEditor.class, "MSG_ValidXPath"); // NOI18N
173: UserNotification.showMessage(msg);
174: }
175: }
176: });
177:
178: SoaUiUtil.activateInlineMnemonics(this );
179: }
180:
181: public boolean initControls() {
182: return true;
183: }
184:
185: public void setSelectedValue(String newValue) {
186: txtExpression.setText(newValue);
187: }
188:
189: public String getSelectedValue() {
190: return txtExpression.getText();
191: }
192:
193: public boolean afterClose() {
194: return true;
195: }
196:
197: public boolean unsubscribeListeners() {
198: return true;
199: }
200:
201: public boolean subscribeListeners() {
202: return true;
203: }
204:
205: private static FileObject getPaletteFolder(String folderName) {
206: FileObject paletteFolder = null;
207: FileSystem fs = Repository.getDefault().getDefaultFileSystem();
208: paletteFolder = fs.findResource(folderName);
209: return paletteFolder;
210: }
211:
212: private void addXPath(AxiomNode node) {
213: XslModel model = myMapper.getContext().getXSLModel();
214: AbstractDocumentComponent adc = (AbstractDocumentComponent) model
215: .getStylesheet();
216: //
217: String oldText = txtExpression.getText();
218: int oldSelectionStart = txtExpression.getSelectionStart();
219: int oldSelectionEnd = txtExpression.getSelectionEnd();
220: //
221: StringBuilder text = new StringBuilder();
222: if (needWhitespaceBefore(oldText, oldSelectionStart)) {
223: text.append(" "); // NOI18N
224: }
225: text.append(AxiomUtils.calculateSimpleXPath(node, adc));
226: if (needWhitespaceAfter(oldText, oldSelectionEnd)) {
227: text.append(" "); // NOI18N
228: }
229: //
230: int selectionStart = oldSelectionStart;
231: int selectionEnd = oldSelectionStart + text.length();
232: //
233: txtExpression.replaceSelection(text.toString());
234: txtExpression.setCaretPosition(selectionEnd);
235: // txtExpression.setSelectionStart(selectionStart);
236: // txtExpression.setSelectionEnd(selectionEnd);
237: txtExpression.requestFocus();
238: }
239:
240: private void addFunction(ItemNode funcItemNode) {
241: XpathPaletteItemInfo info = funcItemNode.getItemInfo();
242: //
243: if (info != null) {
244: String oldText = txtExpression.getText();
245: int oldSelectionStart = txtExpression.getSelectionStart();
246: int oldSelectionEnd = txtExpression.getSelectionEnd();
247: int selectionStart = oldSelectionStart;
248: int selectionEnd = oldSelectionStart;
249: //
250: StringBuilder text = new StringBuilder();
251: if (info.isOperator()) {
252: if (needWhitespaceBefore(oldText, oldSelectionStart)) {
253: text.append(" "); // NOI18N
254: }
255: text.append(info.getOperation()); // NOI18N
256: if (needWhitespaceAfter(oldText, oldSelectionEnd)) {
257: text.append(" "); // NOI18N
258: }
259: selectionStart = oldSelectionStart + text.length();
260: selectionEnd = selectionStart;
261: } else if (info.isFunction()) {
262: if (needWhitespaceBefore(oldText, oldSelectionStart)) {
263: text.append(" "); // NOI18N
264: }
265: int maxInput = info.getMaxInput();
266: String inp1, inp2, inp3, inp4;
267: switch (maxInput) {
268: case 1:
269: inp1 = (String) info.getItemAttribute(INPUT_PARAM
270: + "1"); // NOI18N
271: text.append(info.getOperation()).append("("); // NOI18N
272: selectionStart = oldSelectionStart + text.length();
273: text.append(inp1); // NOI18N
274: selectionEnd = oldSelectionStart + text.length();
275: text.append(")"); // NOI18N
276: break;
277: case 2:
278: inp1 = (String) info.getItemAttribute(INPUT_PARAM
279: + "1"); // NOI18N
280: text.append(info.getOperation()).append("("); // NOI18N
281: selectionStart = oldSelectionStart + text.length();
282: text.append(inp1); // NOI18N
283: selectionEnd = oldSelectionStart + text.length();
284: //
285: inp2 = (String) info.getItemAttribute(INPUT_PARAM
286: + "2"); // NOI18N
287: text.append(", ").append(inp2); // NOI18N
288: //
289: text.append(")"); // NOI18N
290: break;
291: case 3:
292: inp1 = (String) info.getItemAttribute(INPUT_PARAM
293: + "1"); // NOI18N
294: text.append(info.getOperation()).append("("); // NOI18N
295: selectionStart = oldSelectionStart + text.length();
296: text.append(inp1); // NOI18N
297: selectionEnd = oldSelectionStart + text.length();
298: //
299: inp2 = (String) info.getItemAttribute(INPUT_PARAM
300: + "2"); // NOI18N
301: text.append(", ").append(inp2); // NOI18N
302: //
303: inp3 = (String) info.getItemAttribute(INPUT_PARAM
304: + "3"); // NOI18N
305: text.append(", ").append(inp3); // NOI18N
306: //
307: text.append(")"); // NOI18N
308: break;
309: case 0:
310: default:
311: inp1 = (String) info.getItemAttribute(INPUT_PARAM
312: + "1"); // NOI18N
313: text.append(info.getOperation()).append("("); // NOI18N
314: selectionStart = oldSelectionStart + text.length();
315: selectionEnd = selectionStart;
316: text.append(")"); // NOI18N
317: break;
318: }
319: if (needWhitespaceAfter(oldText, oldSelectionEnd)) {
320: text.append(" "); // NOI18N
321: }
322: }
323: //
324: if (text != null && text.length() > 0) {
325: txtExpression.replaceSelection(text.toString());
326: txtExpression.setCaretPosition(selectionStart);
327: txtExpression.setSelectionStart(selectionStart);
328: txtExpression.setSelectionEnd(selectionEnd);
329: txtExpression.requestFocus();
330: }
331: //
332: // TODO set focus to the expression field
333: // TODO set cursor to appropriate place!!!
334: }
335: }
336:
337: private boolean needWhitespaceBefore(final String text,
338: final int position) {
339: //
340: if (text.length() == 0 || position == 0) {
341: return false;
342: }
343: //
344: char prevChar = text.charAt(position - 1);
345: return !Character.isWhitespace(prevChar)
346: && "(".indexOf(prevChar) < 0;
347: }
348:
349: private boolean needWhitespaceAfter(final String text,
350: final int position) {
351: //
352: if (text.length() == 0 || position == text.length()) {
353: return false;
354: }
355: //
356: char charAt = text.charAt(position);
357: return !Character.isWhitespace(charAt)
358: && ",)".indexOf(charAt) < 0;
359: }
360:
361: private boolean checkSyntax() {
362: boolean result = true;
363: //
364: String expr = txtExpression.getText();
365: if (expr == null || expr.length() == 0) {
366: return result;
367: }
368: XPathModel xpImpl = AbstractXPathModelHelper.getInstance()
369: .newXPathModel();
370: try {
371: XPathExpression xPath = xpImpl.parseExpression(expr);
372: // String exprString = xPath.getExpressionString();
373: // UserNotification.showMessage(exprString);
374: } catch (XPathException xpe) {
375: String errorMessage = null;
376: Throwable cause = xpe.getCause();
377: if (cause != null) {
378: errorMessage = cause.getMessage();
379: }
380: if (errorMessage == null) {
381: errorMessage = xpe.getMessage();
382: }
383: //
384: UserNotification.showMessage(errorMessage);
385: result = false;
386: }
387: return result;
388: }
389:
390: public Validator getValidator() {
391: if (myValidator == null) {
392: myValidator = new DefaultValidator(this ,
393: ExpressionEditor.class) {
394:
395: public void doFastValidation() {
396: }
397:
398: @Override
399: public void doDetailedValidation() {
400: super .doDetailedValidation();
401: //
402: if (!checkSyntax()) {
403: addReason(new Reason(Severity.ERROR,
404: "Wrong XPath syntax")); // NOI18N
405: }
406: }
407:
408: };
409: }
410: return myValidator;
411: }
412:
413: /** This method is called from within the constructor to
414: * initialize the form.
415: * WARNING: Do NOT modify this code. The content of this method is
416: * always regenerated by the Form Editor.
417: */
418: // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
419: private void initComponents() {
420:
421: lblSchema = new javax.swing.JLabel();
422: lblFunctions = new javax.swing.JLabel();
423: lblExpression = new javax.swing.JLabel();
424: scrSchema = new javax.swing.JScrollPane();
425: treeSchema = new javax.swing.JTree();
426: scrFunctions = new javax.swing.JScrollPane();
427: treeFunctions = new javax.swing.JTree();
428: scrExpression = new javax.swing.JScrollPane();
429: txtExpression = new javax.swing.JTextArea();
430: btnCheckSyntax = new javax.swing.JButton();
431:
432: lblSchema.setLabelFor(treeSchema);
433: lblSchema.setText(org.openide.util.NbBundle.getMessage(
434: ExpressionEditor.class, "LBL_Schema")); // NOI18N
435:
436: lblFunctions.setLabelFor(treeFunctions);
437: lblFunctions.setText(org.openide.util.NbBundle.getMessage(
438: ExpressionEditor.class, "LBL_Functions")); // NOI18N
439:
440: lblExpression.setLabelFor(txtExpression);
441: lblExpression.setText(org.openide.util.NbBundle.getMessage(
442: ExpressionEditor.class, "LBL_Expression")); // NOI18N
443:
444: scrSchema.setViewportView(treeSchema);
445:
446: scrFunctions.setViewportView(treeFunctions);
447:
448: txtExpression.setColumns(20);
449: txtExpression.setRows(5);
450: scrExpression.setViewportView(txtExpression);
451:
452: btnCheckSyntax.setText(org.openide.util.NbBundle.getMessage(
453: ExpressionEditor.class, "BTN_CheckSyntax")); // NOI18N
454:
455: org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(
456: this );
457: this .setLayout(layout);
458: layout
459: .setHorizontalGroup(layout
460: .createParallelGroup(
461: org.jdesktop.layout.GroupLayout.LEADING)
462: .add(
463: org.jdesktop.layout.GroupLayout.TRAILING,
464: layout
465: .createSequentialGroup()
466: .addContainerGap()
467: .add(
468: layout
469: .createParallelGroup(
470: org.jdesktop.layout.GroupLayout.TRAILING)
471: .add(
472: org.jdesktop.layout.GroupLayout.LEADING,
473: scrExpression,
474: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
475: 655,
476: Short.MAX_VALUE)
477: .add(
478: layout
479: .createSequentialGroup()
480: .add(
481: layout
482: .createParallelGroup(
483: org.jdesktop.layout.GroupLayout.LEADING)
484: .add(
485: layout
486: .createSequentialGroup()
487: .add(
488: scrSchema,
489: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
490: 435,
491: Short.MAX_VALUE)
492: .add(
493: 7,
494: 7,
495: 7))
496: .add(
497: layout
498: .createSequentialGroup()
499: .add(
500: lblSchema)
501: .addPreferredGap(
502: org.jdesktop.layout.LayoutStyle.RELATED)))
503: .addPreferredGap(
504: org.jdesktop.layout.LayoutStyle.RELATED)
505: .add(
506: layout
507: .createParallelGroup(
508: org.jdesktop.layout.GroupLayout.LEADING)
509: .add(
510: lblFunctions)
511: .add(
512: scrFunctions,
513: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
514: 213,
515: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
516: .add(
517: layout
518: .createSequentialGroup()
519: .add(
520: lblExpression)
521: .addPreferredGap(
522: org.jdesktop.layout.LayoutStyle.RELATED,
523: 500,
524: Short.MAX_VALUE)
525: .add(
526: btnCheckSyntax)))
527: .addContainerGap()));
528: layout
529: .setVerticalGroup(layout
530: .createParallelGroup(
531: org.jdesktop.layout.GroupLayout.LEADING)
532: .add(
533: org.jdesktop.layout.GroupLayout.TRAILING,
534: layout
535: .createSequentialGroup()
536: .addContainerGap()
537: .add(
538: layout
539: .createParallelGroup(
540: org.jdesktop.layout.GroupLayout.BASELINE)
541: .add(lblSchema)
542: .add(
543: lblFunctions))
544: .addPreferredGap(
545: org.jdesktop.layout.LayoutStyle.RELATED)
546: .add(
547: layout
548: .createParallelGroup(
549: org.jdesktop.layout.GroupLayout.LEADING)
550: .add(
551: scrFunctions,
552: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
553: 250,
554: Short.MAX_VALUE)
555: .add(
556: scrSchema,
557: org.jdesktop.layout.GroupLayout.DEFAULT_SIZE,
558: 250,
559: Short.MAX_VALUE))
560: .addPreferredGap(
561: org.jdesktop.layout.LayoutStyle.RELATED)
562: .add(
563: layout
564: .createParallelGroup(
565: org.jdesktop.layout.GroupLayout.BASELINE)
566: .add(
567: btnCheckSyntax)
568: .add(
569: lblExpression))
570: .addPreferredGap(
571: org.jdesktop.layout.LayoutStyle.RELATED)
572: .add(
573: scrExpression,
574: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE,
575: 115,
576: org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)));
577:
578: lblSchema.getAccessibleContext().setAccessibleName(
579: org.openide.util.NbBundle.getMessage(
580: ExpressionEditor.class, "ACSN_LBL_Schema")); // NOI18N
581: lblSchema.getAccessibleContext().setAccessibleDescription(
582: org.openide.util.NbBundle.getMessage(
583: ExpressionEditor.class, "ACSD_LBL_Schema")); // NOI18N
584: lblFunctions.getAccessibleContext().setAccessibleName(
585: org.openide.util.NbBundle.getMessage(
586: ExpressionEditor.class, "ACSN_LBL_Functions")); // NOI18N
587: lblFunctions.getAccessibleContext().setAccessibleDescription(
588: org.openide.util.NbBundle.getMessage(
589: ExpressionEditor.class, "ACSD_LBL_Functions")); // NOI18N
590: lblExpression.getAccessibleContext().setAccessibleName(
591: org.openide.util.NbBundle.getMessage(
592: ExpressionEditor.class, "ACSN_LBL_Expression")); // NOI18N
593: lblExpression.getAccessibleContext().setAccessibleDescription(
594: org.openide.util.NbBundle.getMessage(
595: ExpressionEditor.class, "ACSD_LBL_Expression")); // NOI18N
596: btnCheckSyntax.getAccessibleContext()
597: .setAccessibleName(
598: org.openide.util.NbBundle.getMessage(
599: ExpressionEditor.class,
600: "ACSN_BTN_CheckSyntax")); // NOI18N
601: btnCheckSyntax.getAccessibleContext()
602: .setAccessibleDescription(
603: org.openide.util.NbBundle.getMessage(
604: ExpressionEditor.class,
605: "ACSD_BTN_CheckSyntax")); // NOI18N
606: }// </editor-fold>//GEN-END:initComponents
607:
608: // Variables declaration - do not modify//GEN-BEGIN:variables
609: private javax.swing.JButton btnCheckSyntax;
610: private javax.swing.JLabel lblExpression;
611: private javax.swing.JLabel lblFunctions;
612: private javax.swing.JLabel lblSchema;
613: private javax.swing.JScrollPane scrExpression;
614: private javax.swing.JScrollPane scrFunctions;
615: private javax.swing.JScrollPane scrSchema;
616: private javax.swing.JTree treeFunctions;
617: private javax.swing.JTree treeSchema;
618: private javax.swing.JTextArea txtExpression;
619: // End of variables declaration//GEN-END:variables
620:
621: }
|