View Javadoc

1   /*
2    * Copyright 1999-2006 Faculty of Mathematics, Physics
3    * and Informatics, Comenius University, Bratislava. This file is protected by
4    * the Mozilla Public License version 1.1 (the License); you may not use this
5    * file except in compliance with the License. You may obtain a copy of the
6    * License at http://euromath2.sourceforge.net/license.html Unless required by
7    * applicable law or agreed to in writing, software distributed under the
8    * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
9    * OF ANY KIND, either express or implied. See the License for the specific
10   * language governing permissions and limitations under the License.
11   */
12  package sk.uniba.euromath.plugin.views.outline;
13  
14  import java.util.ArrayList;
15  import java.util.HashMap;
16  import java.util.LinkedList;
17  import java.util.List;
18  import java.util.Map;
19  import java.util.Queue;
20  
21  import org.eclipse.core.runtime.IStatus;
22  import org.eclipse.jface.viewers.ITreeContentProvider;
23  import org.eclipse.jface.viewers.Viewer;
24  import org.w3c.dom.Attr;
25  import org.w3c.dom.CDATASection;
26  import org.w3c.dom.Comment;
27  import org.w3c.dom.Element;
28  import org.w3c.dom.EntityReference;
29  import org.w3c.dom.NamedNodeMap;
30  import org.w3c.dom.Node;
31  import org.w3c.dom.NodeList;
32  import org.w3c.dom.ProcessingInstruction;
33  import org.w3c.dom.Text;
34  
35  import sk.uniba.euromath.Const;
36  import sk.uniba.euromath.EuroMath;
37  import sk.uniba.euromath.plugin.views.outline.items.AttributeOutlineItem;
38  import sk.uniba.euromath.plugin.views.outline.items.CDataOutlineItem;
39  import sk.uniba.euromath.plugin.views.outline.items.CommentOutlineItem;
40  import sk.uniba.euromath.plugin.views.outline.items.ElementOutlineItem;
41  import sk.uniba.euromath.plugin.views.outline.items.EntityOutlineItem;
42  import sk.uniba.euromath.plugin.views.outline.items.OutlineItem;
43  import sk.uniba.euromath.plugin.views.outline.items.PIOutlineItem;
44  import sk.uniba.euromath.plugin.views.outline.items.TextOutlineItem;
45  import sk.uniba.euromath.plugin.views.outline.lang.Messages;
46  
47  /***
48   * Tree xml node structure content provider. Provided content is tree of outline
49   * items. Alows to configure which types of nodes are shown. Has auto refresh.
50   * 
51   * @author Tomáš Studva 2.11.2005
52   */
53  public class XMLAccessContentProvider implements ITreeContentProvider {
54  
55      /***
56       * Flag, if internal EM2 attributes should be shown.
57       */
58      protected static boolean showInternalAttributes = false;
59  
60      /***
61       * Root outline item. Is invisible and abstract, don't corresponds to any
62       * node form xml.
63       */
64      private final TopLevelOutlineItem invisibleRoot;
65  
66      /***
67       * Specifies if to refresh, when needed.
68       */
69      private boolean autoRefresh = true;
70  
71      /***
72       * Map from model to outline. One node is associated with one or zero outline item.
73       */
74      private final Map<Node, OutlineItem> nodeItemMap = new HashMap<Node, OutlineItem>();
75  
76      /***
77       * Holds which node types to show.
78       */
79      private final Map<Short, Boolean> visibilityFlagMap = new HashMap<Short, Boolean>();
80  
81      /***
82       * Last content(input).
83       */
84      private Object lastInput;
85  
86      /***
87       * Constructor. Refreshes content. Content is empty, only invisible root exists.
88       */
89      public XMLAccessContentProvider() {
90          super();
91          this.invisibleRoot = new TopLevelOutlineItem();
92          showAll();
93      }
94  
95      /***
96       * 
97       * @param parent
98       * @param xmlNode
99       */
100     protected void addToTree(OutlineItem parent, Node xmlNode) {
101 
102         OutlineItem current = null;
103         Node node;
104 
105         if ((xmlNode != null) && hasToBeShown(xmlNode)) {
106             current = createItem(xmlNode);
107             current.setParent(parent);
108             parent.addChild(current);
109 
110             NamedNodeMap attrs = xmlNode.getAttributes();
111             if (attrs != null) {
112                 for (int i = 0; i < attrs.getLength(); i++) {
113                     node = attrs.item(i);
114                     addToTree(current, node);
115                 }
116             }
117 
118             NodeList children = xmlNode.getChildNodes();
119             for (int i = 0; i < children.getLength(); i++) {
120                 node = children.item(i);
121                 addToTree(current, node);
122             }
123         }
124 
125     }
126 
127     /***
128      * 
129      * @param topDataNode
130      */
131     protected void build(Node topDataNode) {
132         clear();
133         addToTree(getInvisibleRoot(), topDataNode);
134     }
135 
136     /***
137      * 
138      *
139      */
140     protected void clear() {
141         getInvisibleRoot().removeChild(getInvisibleRoot().getChild());
142     }
143 
144     /***
145      * Creates outline item for node.
146      * @param model node
147      * @return new created outline item for node model
148      */
149     protected OutlineItem createItem(Node model) {
150 
151         short type = model.getNodeType();
152 
153         OutlineItem result = null;
154 
155         // REFACTOR: a factory would be useful
156         switch (type) {
157         case Node.ATTRIBUTE_NODE:
158             result = new AttributeOutlineItem((Attr) model);
159             break;
160         case Node.CDATA_SECTION_NODE:
161             result = new CDataOutlineItem((CDATASection) model);
162             break;
163         case Node.COMMENT_NODE:
164             result = new CommentOutlineItem((Comment) model);
165             break;
166         case Node.ELEMENT_NODE:
167             result = new ElementOutlineItem((Element) model);
168             break;
169         case Node.ENTITY_REFERENCE_NODE:
170             result = new EntityOutlineItem((EntityReference) model);
171             break;
172         case Node.PROCESSING_INSTRUCTION_NODE:
173             result = new PIOutlineItem((ProcessingInstruction) model);
174             break;
175         case Node.TEXT_NODE:
176             result = new TextOutlineItem((Text) model);
177             break;
178         default:
179             EuroMath.log(IStatus.ERROR, 0, Messages.getString("XMLAccessContentProvider.0") //$NON-NLS-1$
180                     + model.getClass().getName() + Messages.getString("XMLAccessContentProvider.1"), //$NON-NLS-1$
181                     null);
182             break;
183         }
184 
185         if (result != null) {
186             this.nodeItemMap.put(model, result);
187         }
188         return result;
189     }
190 
191     public void dispose() {
192         // nothing to do
193     }
194 
195     /*
196      * (non-Javadoc)
197      * 
198      * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
199      */
200     public Object[] getChildren(Object parent) {
201         assert (parent instanceof OutlineItem);
202         return ((OutlineItem) parent).getChildren().toArray();
203     }
204 
205     /*
206      * (non-Javadoc)
207      * 
208      * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
209      */
210     public Object[] getElements(Object parent) {
211         return getInvisibleRoot().getChildren().toArray();
212     }
213 
214     /***
215      * Returns OutlineItem which displays node or null if outline view don't
216      * have outline item which correspond to that node.
217      * 
218      * @param node
219      *            which is displayed in outline by some outline item
220      * @return outline item which displays node or null if no such node exists
221      */
222     public OutlineItem getItem(Node node) {
223 
224         // quick solution:
225         if (this.nodeItemMap.containsKey(node)) {
226             return this.nodeItemMap.get(node);
227         }
228 
229         // full tree traversal:
230         Queue<OutlineItem> queue = new LinkedList<OutlineItem>();
231         queue.add(getInvisibleRoot());
232 
233         while (queue.size() > 0) {
234             if (queue.peek().getModel() == node)
235                 return queue.peek();
236             List<OutlineItem> children = queue.remove().getChildren();
237             queue.addAll(children);
238         }
239         return null;
240     }
241 
242     /*
243      * (non-Javadoc)
244      * 
245      * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
246      */
247     public Object getParent(Object element) {
248         if ((element == null) || !(element instanceof OutlineItem))
249             throw new IllegalArgumentException(
250                     Messages.getString("XMLAccessContentProvider.2")); //$NON-NLS-1$
251         return ((OutlineItem) element).getParent();
252     }
253 
254     /*
255      * (non-Javadoc)
256      * 
257      * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
258      */
259     public boolean hasChildren(Object parent) {
260         if (parent == null)
261             return false;
262         assert (parent instanceof OutlineItem);
263         return ((OutlineItem) parent).getChildren().size() > 0;
264     }
265 
266     /***
267      * Computes if node should be shown.
268      * 
269      * @param node
270      *            the node
271      * @return true if node should be shown
272      */
273     protected boolean hasToBeShown(Node node) {
274         // if internal attribute, use flag
275         if ((node.getNodeType() == Node.ATTRIBUTE_NODE)
276                 && (node.getNamespaceURI() != null)
277                 && (node.getNamespaceURI().equals(Const.EM_URI)))
278             return showInternalAttributes;
279 
280         // use visibility flags
281         Object o = getVisibilityFlagMap().get(new Short(node.getNodeType()));
282         if (o == null)
283             throw new IllegalArgumentException(
284                     Messages.getString("XMLAccessContentProvider.3")); //$NON-NLS-1$
285         return ((Boolean) o).booleanValue();
286 
287     }
288 
289     /***
290      * @return Returns the visibilityFlagMap.
291      */
292     protected Map<Short, Boolean> getVisibilityFlagMap() {
293         return this.visibilityFlagMap;
294     }
295 
296     /*
297      * (non-Javadoc)
298      * 
299      * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer,
300      *      java.lang.Object, java.lang.Object)
301      */
302     public void inputChanged(Viewer v, Object oldInput, Object newInput) {
303         this.lastInput = newInput;
304         if (newInput == null) {
305             clear();
306         } else {
307             assert ((newInput instanceof Node));
308             build((Node) newInput);
309         }
310     }
311 
312     /***
313      * Refreshes the content.
314      *
315      */
316     protected void refresh() {
317         inputChanged(null, null, this.lastInput);
318     }
319 
320     /***
321      * Sets visibility to nodes of type nodeType. If show is true, nodes of that
322      * type will be shown.
323      * 
324      * @param nodeType
325      *            type of node
326      * @param show
327      *            specifies if to show
328      */
329     public void setShowType(short nodeType, boolean show) {
330 
331         getVisibilityFlagMap().put(new Short(nodeType), new Boolean(show));
332 
333         if (isAutoRefresh()) {
334             refresh();
335         }
336     }
337 
338     /***
339      * @return Returns the autoRefresh.
340      */
341     protected boolean isAutoRefresh() {
342         return this.autoRefresh;
343     }
344 
345     /***
346      * @param autoRefresh The autoRefresh to set.
347      */
348     protected void setAutoRefresh(boolean autoRefresh) {
349         this.autoRefresh = autoRefresh;
350     }
351 
352     /***
353      * Sets visibility of all nodes types to true and refreshes content if auto
354      * refresh is on.
355      */
356     public void showAll() {
357         boolean old = isAutoRefresh();
358         setAutoRefresh(false);
359         setShowType(Node.ATTRIBUTE_NODE, true);
360         setShowType(Node.CDATA_SECTION_NODE, true);
361         setShowType(Node.COMMENT_NODE, true);
362         setShowType(Node.ELEMENT_NODE, true);
363         setShowType(Node.PROCESSING_INSTRUCTION_NODE, true);
364         setShowType(Node.TEXT_NODE, true);
365         setShowType(Node.ENTITY_REFERENCE_NODE, true);
366         
367 
368         setAutoRefresh(old);
369         if (isAutoRefresh())
370             refresh();
371     }
372 
373     /***
374      * Outline item for holding only one child. Corresponds to no model.
375      * 
376      * @author Tomáš Studva 2.11.2005
377      */
378     private class TopLevelOutlineItem extends OutlineItem {
379 
380         /***
381          * The only child of this item.
382          */
383         private OutlineItem child;
384 
385         /***
386          * Constructor. No model is passed, no is assumed.
387          */
388         public TopLevelOutlineItem() {
389             super(null);
390         }
391 
392         /***
393          * Overrides currently holded child. Remenber only one child has this
394          * item.
395          */
396         @Override
397         public void addChild(OutlineItem child) {
398             this.child = child;
399         }
400         
401         /***
402          * Overrides currently holded child. Remenber only one child has this
403          * item.
404          */
405         @Override
406         public void removeChild(OutlineItem child) {
407             if (getChild() == child)
408                 setChild(null);
409         }
410 
411         /***
412          * @param child The child to set.
413          */
414         protected void setChild(OutlineItem child) {
415             this.child = child;
416         }
417 
418         /***
419          * Returns the only child.
420          * @return the child
421          */
422         public OutlineItem getChild() {
423             return this.child;
424         }
425 
426         /***
427          * Returns list with the only child.
428          */
429         @Override
430         public List<OutlineItem> getChildren() {
431             List<OutlineItem> children = new ArrayList<OutlineItem>();
432             children.add(getChild());
433             return children;
434         }
435 
436     }
437 
438     /***
439      * @return Returns the invisibleRoot.
440      */
441     protected TopLevelOutlineItem getInvisibleRoot() {
442         return this.invisibleRoot;
443     }
444 
445 }