View Javadoc

1   /*
2    * $Id$
3    *
4    * The contents of this file are subject to the Mozilla Public License 
5    * Version 1.1 (the "License"); you may not use this file except in 
6    * compliance with the License. You may obtain a copy of the License at 
7    * http://www.mozilla.org/MPL/ 
8    *
9    * Software distributed under the License is distributed on an "AS IS" basis, 
10   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
11   * for the specific language governing rights and limitations under the License.
12   *
13   * The Original Code is XML Hammer code. (org.xmlhammer.*)
14   *
15   * The Initial Developer of the Original Code is Edwin Dankert. Portions created 
16   * by the Initial Developer are Copyright (C) 2005 - 2006 the Initial Developer. 
17   * All Rights Reserved.
18   *
19   * Contributor(s): Edwin Dankert <edankert@gmail.com>
20   */
21  
22  package org.xmlhammer.gui.xpath;
23  
24  import java.awt.Font;
25  import java.awt.event.ItemEvent;
26  import java.awt.event.ItemListener;
27  import java.util.ArrayList;
28  import java.util.List;
29  
30  import javax.swing.Box;
31  import javax.swing.Icon;
32  import javax.swing.ImageIcon;
33  import javax.swing.JComboBox;
34  import javax.swing.JLabel;
35  import javax.swing.JPanel;
36  import javax.swing.JTextField;
37  import javax.swing.border.EmptyBorder;
38  import javax.swing.event.DocumentEvent;
39  import javax.swing.event.DocumentListener;
40  import javax.xml.xpath.XPathExpressionException;
41  import javax.xml.xpath.XPathFactory;
42  import javax.xml.xpath.XPathFactoryConfigurationException;
43  
44  import org.apache.log4j.Logger;
45  import org.bounce.FormConstraints;
46  import org.bounce.FormLayout;
47  import org.bounce.image.ImageLoader;
48  import org.xmlhammer.PreferencesHandler;
49  import org.xmlhammer.gui.Page;
50  import org.xmlhammer.gui.history.HistoryComboBox;
51  import org.xmlhammer.gui.history.HistoryComboBoxModel;
52  import org.xmlhammer.gui.history.HistoryUtilities;
53  import org.xmlhammer.gui.overview.ComboBoxNode;
54  import org.xmlhammer.gui.overview.OverviewNode;
55  import org.xmlhammer.gui.overview.OverviewTreeModel;
56  import org.xmlhammer.gui.util.UndoableComboBoxItemListener;
57  import org.xmlhammer.model.jaxp.Feature;
58  import org.xmlhammer.model.jaxp.JAXPXPathFactory;
59  import org.xmlhammer.model.jaxp.Mapping;
60  import org.xmlhammer.model.project.Project;
61  import org.xmlhammer.model.tools.xpath.XPath;
62  
63  /***
64   * Input Panel.
65   * 
66   * Allows to select either one URI, multiple URIs or 
67   * a range of files.
68   * 
69   * @version $Revision$, $Date$
70   * @author Edwin Dankert <edankert@gmail.com>
71   */
72  
73  public class XPathPanel extends JPanel {
74      private static final long serialVersionUID = -6021755010826846525L;
75  
76      private static final ImageIcon ERROR_ICON = ImageLoader.get().getImage( "/org/xmlhammer/gui/icons/obj16/error_obj.gif");
77      private static final ImageIcon TEXT_FIELD_ICON = ImageLoader.get().getImage( "/org/xmlhammer/gui/icons/elcl16/textfield_obj.gif");
78      private static final String[] RETURN_TYPES = { "BOOLEAN", "NODE", "NODESET", "NUMBER", "STRING"};
79  
80      private Page page                       = null;
81      private JLabel errorLabel               = null;
82      private ArrayList<OverviewNode> nodes   = null;
83      private HistoryComboBox xpathField      = null;
84      private JComboBox returnTypeField       = null;
85      private XPathNode node                  = null;
86  
87  	/***
88  	 * @param view the underlying view.
89  	 */
90  	public XPathPanel(XPathPage page) {
91  		super(new FormLayout( 10, 2));
92          
93          this.page = page;
94  		setBorder( new EmptyBorder( 10, 10, 20, 10));
95  
96  		xpathField = new HistoryComboBox(page, new HistoryComboBoxModel(HistoryUtilities.getInstance().getExpressions()));
97          ((JTextField)xpathField.getEditor().getEditorComponent()).getDocument().addDocumentListener(new DocumentListener() {
98              public void insertUpdate(DocumentEvent event) {
99                  checkXPath();
100             }
101 
102             public void removeUpdate(DocumentEvent arg0) {
103                 checkXPath();
104             }
105 
106             public void changedUpdate(DocumentEvent arg0) {}
107         });
108 		xpathField.setToolTipText( "Specify the XPath expression.");
109         
110         errorLabel = new JLabel(ERROR_ICON);
111         errorLabel.setVisible(false);
112         errorLabel.setHorizontalAlignment(JLabel.LEFT);
113         
114         if (page != null) {
115             page.getProjectView().getFieldManager().addField( xpathField);
116         }
117         
118         returnTypeField = new JComboBox( RETURN_TYPES);
119         returnTypeField.setFont( returnTypeField.getFont().deriveFont(Font.PLAIN));
120         returnTypeField.setToolTipText( "Specify the XPath return type.");
121 
122         if (page != null) {
123             page.getProjectView().getFieldManager().addField(returnTypeField);
124         }
125         
126         returnTypeField.addItemListener(new UndoableComboBoxItemListener(page, returnTypeField));
127 
128         add( new JLabel( "Expression:"), new FormConstraints( FormConstraints.LEFT, FormConstraints.RIGHT));
129 		add( xpathField, FormLayout.RIGHT_FILL);
130         add( new JLabel(" "), FormLayout.LEFT);
131         add( errorLabel, FormLayout.RIGHT_FILL);
132         add( Box.createVerticalStrut(10), FormLayout.FULL_FILL);
133 		add( new JLabel( "Return Type:"), new FormConstraints( FormConstraints.LEFT, FormConstraints.RIGHT));
134 		add( returnTypeField, FormLayout.RIGHT);
135 		
136 		nodes = new ArrayList<OverviewNode>();
137         node = new XPathNode(page, xpathField);
138 		nodes.add(node);
139         nodes.add(new ComboBoxNode(page, returnTypeField, "returnType"));
140 	}
141     
142     private void checkXPath() {
143         Throwable cause = null;
144         
145         try {
146             errorLabel.setVisible(false);
147             node.setError(null);
148             compileXPath(xpathField.getValue());
149         } catch (XPathFactoryConfigurationException e) {
150             cause = e;
151         } catch (XPathExpressionException e) {
152             cause = e;
153         } catch (Exception e) {
154             // don't do anything, just log
155             Logger.getLogger(getClass()).debug(e);
156         }
157         
158         if (cause != null) {
159             while (cause.getCause() != null) {
160                 cause = cause.getCause();
161             }
162     
163             errorLabel.setText(cause.getMessage());
164             errorLabel.setVisible(true);
165             node.setError(cause.getMessage());
166         }
167     }
168 	
169 	/***
170 	 * @return the XPath settings.
171 	 */
172 	public XPath getXPath() {
173 		XPath path = new XPath();
174 		
175         path.setExpression( xpathField.getValue());
176         path.setReturnType( (String)returnTypeField.getSelectedItem());
177 		
178 		return path;
179 	}
180 
181 	public void setXPath(XPath xpath) {
182         Logger.getLogger(this.getClass()).debug( "setXPath( "+xpath+")");
183 		if ( xpath != null) {
184 			xpathField.setValue( xpath.getExpression());
185 			returnTypeField.setSelectedItem( xpath.getReturnType());
186 //
187 //            checkXPath();
188 		} else {
189 			xpathField.setValue( null);
190             returnTypeField.setSelectedItem( RETURN_TYPES[2]);
191 		}
192 	}
193     
194     String getXPathValue() {
195         return xpathField.getValue();
196     }
197     
198     String getReturnType() {
199         return (String)returnTypeField.getSelectedItem();
200     }
201 	
202 	/* (non-Javadoc)
203 	 * @see org.xmlhammer.gui.Page#getChildNodes()
204 	 */
205 	public ArrayList<OverviewNode> getChildNodes() {
206 		return nodes;
207 	}
208     
209     public void dispose() {
210         
211     }
212     
213     public void preferencesUpdated() {
214         checkXPath();
215         node.nodeChanged();
216     }
217 
218     private class XPathNode implements OverviewNode, ItemListener, DocumentListener {
219 		private OverviewNode parent   = null;
220 		private JComboBox xpathField  = null;
221         private String error          = null;
222 		
223 		public XPathNode( OverviewNode parent, JComboBox xpathField)  {
224 			this.xpathField = xpathField;
225 			this.parent = parent;
226 			
227 			((JTextField)xpathField.getEditor().getEditorComponent()).getDocument().addDocumentListener( this);
228 		}
229 		
230 	    public String getNodeName() {
231 	        return (String)xpathField.getEditor().getItem() + " (expression)";
232 	    }
233 	
234 	    public ArrayList<OverviewNode> getChildNodes() {
235 	        return new ArrayList<OverviewNode>();
236 	    }
237 	
238 	    public OverviewNode getParentNode() {
239 	        return parent;
240 	    }
241 	
242 	    public Icon getNodeIcon() {
243 	//    	if ( subdirs.isSelected()) { 
244 	//    		return SUBDIR_ICON;
245 	//    	}
246 	
247 	    	return TEXT_FIELD_ICON;
248 	    }
249 	    
250 		public void itemStateChanged( ItemEvent e) {
251 			nodeChanged();
252 		}
253 	
254 		public void nodeChanged() {
255 	    	OverviewNode node = parent;
256 	    	
257 	    	while (node != null && !(node.getParentNode() instanceof OverviewTreeModel)) {
258 	    		node = node.getParentNode();
259 	    	}
260 	    	
261 			if (node != null) {
262 	    		((OverviewTreeModel)node.getParentNode()).nodePathChanged( this);
263 	    	}
264 	    }
265 	
266         public void setError(String error) {
267             this.error = error;
268         }
269         
270         public String getError() {
271             return error;
272         }
273 
274         public void insertUpdate(DocumentEvent arg0) {
275             nodeChanged();
276         }
277 
278         public void removeUpdate(DocumentEvent arg0) {
279             nodeChanged();
280         }
281 
282         public void changedUpdate(DocumentEvent arg0) {}
283 	}
284     
285     public XPathFactory getXPathFactory() throws XPathFactoryConfigurationException {
286         String objectModel = XPathFactory.DEFAULT_OBJECT_MODEL_URI;
287         JAXPXPathFactory.Settings settings = getXPathFactorySettings();
288         
289         if ( settings.getValue() != null) {
290             System.setProperty( XPathFactory.DEFAULT_PROPERTY_NAME, settings.getValue());
291         }
292         
293         if ( settings.getObjectModel() != null) {
294             objectModel = settings.getObjectModel();
295         }
296         
297         // Get a instance of XPathFactory with ObjectModel URL parameter. If
298         // no parameter is mentioned then default DOM Object Model is used
299         XPathFactory factory = XPathFactory.newInstance( objectModel);
300 
301         List<Feature> features = getXPathFactoryFeatures();
302 
303         for ( Feature feature : features) {
304             factory.setFeature( feature.getName(), feature.isEnabled());
305         }
306         
307         return factory;
308     }
309 
310     private void compileXPath(String value) throws XPathFactoryConfigurationException, XPathExpressionException {
311         XPathFactory factory = getXPathFactory();
312         
313         javax.xml.xpath.XPath xpath = factory.newXPath();
314 
315         NamespaceContextMap nsMap = new NamespaceContextMap();
316 
317         List<Mapping> mappings = getXPathFactoryMappings();
318 
319         for (Mapping mapping : mappings) {
320             nsMap.put( mapping.getPrefix(), mapping.getUri());
321         }
322         
323         xpath.setNamespaceContext( nsMap);
324         
325         xpath.compile(value);
326     }
327     
328     /***
329      * @return the JAXPXPathFactory.Settings, project specific if defined, otherwise from global preferences.
330      */
331     private JAXPXPathFactory.Settings getXPathFactorySettings() {
332         if (page != null) {
333             Project project = page.getProjectView().getProject();
334 
335             if (project.getJAXPSettings().getJAXPXPathFactory().getSettings() != null) {
336                 return project.getJAXPSettings().getJAXPXPathFactory().getSettings();
337             }
338         }
339         
340         return PreferencesHandler.getInstance().getPreferences().getJAXPSettings().getJAXPXPathFactory().getSettings();
341     }
342     
343     /***
344      * @return the JAXPXPathFactory.Features, project specific if defined, otherwise from global preferences.
345      */
346     private List<Feature> getXPathFactoryFeatures() {
347         if (page != null) {
348             Project project = page.getProjectView().getProject();
349             if ( project.getJAXPSettings().getJAXPXPathFactory().getFeatures() != null) {
350                 return project.getJAXPSettings().getJAXPXPathFactory().getFeatures().getFeature();
351             }
352         }
353 
354         return PreferencesHandler.getInstance().getPreferences().getJAXPSettings().getJAXPXPathFactory().getFeatures().getFeature();
355     }
356 
357     /***
358      * @return the JAXPXPathFactory.Mappings, project specific if defined, otherwise from global preferences.
359      */
360     private List<Mapping> getXPathFactoryMappings() {
361         if (page != null) {
362             Project project = page.getProjectView().getProject();
363             if ( project.getJAXPSettings().getJAXPXPathFactory().getMappings() != null) {
364                 return project.getJAXPSettings().getJAXPXPathFactory().getMappings().getMapping();
365             }
366         }
367 
368         return PreferencesHandler.getInstance().getPreferences().getJAXPSettings().getJAXPXPathFactory().getMappings().getMapping();
369     }
370 }