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:
042: /*
043: * ComplexTypeDerivationsReader.java
044: *
045: * Created on October 26, 2005, 11:27 AM
046: *
047: * To change this template, choose Tools | Template Manager
048: * and open the template in the editor.
049: */
050:
051: package org.netbeans.modules.xml.schema.refactoring.query.readers;
052:
053: import java.awt.Color;
054: import java.awt.Image;
055: import java.beans.BeanInfo;
056: import java.text.MessageFormat;
057: import java.util.ArrayList;
058: import java.util.Collection;
059: import java.util.Hashtable;
060: import java.util.Iterator;
061: import java.util.List;
062: import java.util.Map;
063: import java.util.Map.Entry;
064: import java.util.MissingResourceException;
065: import java.util.Set;
066: import java.util.concurrent.ExecutionException;
067: import javax.swing.ImageIcon;
068: import org.netbeans.api.project.SourceGroup;
069: import org.netbeans.modules.refactoring.api.RefactoringElement;
070: import org.netbeans.modules.refactoring.spi.ui.TreeElement;
071: import org.netbeans.modules.refactoring.spi.ui.TreeElementFactory;
072: import org.netbeans.modules.xml.nbprefuse.AnalysisConstants;
073: import org.netbeans.modules.xml.refactoring.spi.SharedUtils;
074: import org.netbeans.modules.xml.refactoring.spi.UIHelper;
075: import org.netbeans.modules.xml.refactoring.spi.AnalysisUtilities;
076: import org.netbeans.modules.xml.schema.model.ComplexContentRestriction;
077: import org.netbeans.modules.xml.schema.model.ComplexExtension;
078: import org.netbeans.modules.xml.schema.model.GlobalComplexType;
079: import org.netbeans.modules.xml.schema.refactoring.SchemaUIHelper;
080: import org.netbeans.modules.xml.schema.refactoring.ui.DisplayInfoVisitor;
081: import org.netbeans.modules.xml.xam.Component;
082: import org.netbeans.modules.xml.xam.Model;
083: import org.netbeans.modules.xml.xam.Named;
084: import org.netbeans.modules.xml.xam.Referenceable;
085: import org.openide.ErrorManager;
086: import org.openide.awt.StatusDisplayer;
087: import org.openide.filesystems.FileObject;
088: import org.openide.filesystems.FileUtil;
089: import org.openide.util.NbBundle;
090: import prefuse.data.Edge;
091: import prefuse.data.Graph;
092: import prefuse.data.Node;
093:
094: /**
095: *
096: * @author Jeri Lockhart
097: *
098: * Reader for Where Used query and Complex Type Derivations query
099: */
100: public class ComplexTypeDerivationsReader {
101:
102: //Derivations view
103: private static final DisplayInfoVisitor div = new DisplayInfoVisitor();
104:
105: public static final prefuse.data.Schema FIND_USAGES_NODES_SCHEMA = new prefuse.data.Schema(); // prefuse graph schema
106: static {
107: FIND_USAGES_NODES_SCHEMA.addColumn(AnalysisConstants.LABEL,
108: String.class, AnalysisConstants.EMPTY_STRING);
109: FIND_USAGES_NODES_SCHEMA.addColumn(AnalysisConstants.ID,
110: String.class, AnalysisConstants.EMPTY_STRING);
111: FIND_USAGES_NODES_SCHEMA.addColumn(
112: AnalysisConstants.COMPONENT_TYPE_NAME, String.class,
113: AnalysisConstants.EMPTY_STRING);
114: FIND_USAGES_NODES_SCHEMA.addColumn(
115: AnalysisConstants.ELEMENT_TYPE, String.class,
116: AnalysisConstants.EMPTY_STRING);
117: // type of a GE, LE, GA, or LA
118:
119: FIND_USAGES_NODES_SCHEMA.addColumn(
120: AnalysisConstants.XML_FILENAME, String.class,
121: AnalysisConstants.EMPTY_STRING);
122: FIND_USAGES_NODES_SCHEMA.addColumn(
123: AnalysisConstants.FILE_OBJECT, FileObject.class);
124: FIND_USAGES_NODES_SCHEMA.addColumn(AnalysisConstants.FILE_TYPE,
125: String.class, AnalysisConstants.EMPTY_STRING);
126: FIND_USAGES_NODES_SCHEMA.addColumn(AnalysisConstants.TOOLTIP,
127: String.class, AnalysisConstants.EMPTY_STRING); // name
128: FIND_USAGES_NODES_SCHEMA.addColumn(
129: AnalysisConstants.XAM_COMPONENT, Component.class);
130: FIND_USAGES_NODES_SCHEMA.addColumn(
131: AnalysisConstants.OPENIDE_NODE,
132: org.openide.nodes.Node.class);
133: FIND_USAGES_NODES_SCHEMA.addColumn(
134: AnalysisConstants.JAVA_AWT_IMAGE, Image.class);
135:
136: // used to set node visible or not visible, depending on whether the
137: // file node is expanded or collapsed
138: // -1 = always visible, any other value matches a
139: // FILE_NODE_FILE_GROUP
140: // the file node itself has a FILE_GROUP of -1 because it is always
141: // visible
142: FIND_USAGES_NODES_SCHEMA.addColumn(
143: AnalysisConstants.FILE_GROUP, int.class, -1);
144: // a File Node has a positive value for this column, other nodes
145: // have a -1 value
146: FIND_USAGES_NODES_SCHEMA.addColumn(
147: AnalysisConstants.FILE_NODE_FILE_GROUP, int.class, -1);
148: // assigned number of schema file group
149:
150: FIND_USAGES_NODES_SCHEMA.addColumn(
151: AnalysisConstants.IS_PRIMITIVE, boolean.class, false); // is builtin type
152: FIND_USAGES_NODES_SCHEMA.addColumn(
153: AnalysisConstants.IS_QUERY_NODE, boolean.class, false);
154: FIND_USAGES_NODES_SCHEMA.addColumn(
155: AnalysisConstants.IS_USAGE_NODE, boolean.class, false);
156: FIND_USAGES_NODES_SCHEMA.addColumn(
157: AnalysisConstants.IS_FILE_NODE, boolean.class, false);
158: FIND_USAGES_NODES_SCHEMA.addColumn(
159: AnalysisConstants.IS_EXPANDED, boolean.class, false);
160: FIND_USAGES_NODES_SCHEMA.addColumn(AnalysisConstants.MOUSEOVER,
161: boolean.class, false);
162: }
163:
164: public static final prefuse.data.Schema FIND_USAGES_EDGES_SCHEMA = new prefuse.data.Schema(); // prefuse graph schema
165: static {
166: FIND_USAGES_EDGES_SCHEMA.addColumn(AnalysisConstants.LABEL,
167: String.class, AnalysisConstants.EMPTY_STRING);
168: FIND_USAGES_EDGES_SCHEMA.addColumn(AnalysisConstants.EDGE_TYPE,
169: String.class, AnalysisConstants.EMPTY_STRING);
170: // "file-edge-type" "generalization", "reference" "composition"
171:
172: FIND_USAGES_EDGES_SCHEMA.addColumn(AnalysisConstants.TOOLTIP,
173: String.class, AnalysisConstants.EMPTY_STRING);
174: // used to set edge visible or not visible, depending on whether the
175: // file node is expanded or collapsed
176: // -1 = always visible, any other value matches a
177: // FILE_NODE_FILE_GROUP
178: // the file node itself has a FILE_GROUP of -1 because it is
179: // always visible
180: FIND_USAGES_EDGES_SCHEMA.addColumn(
181: AnalysisConstants.FILE_GROUP, int.class, -1);
182: }
183:
184: public enum Type {
185: REFERENCE, GENERALIZATION;
186: }
187:
188: /**
189: * Creates a new instance of ComplexTypeDerivationsReader
190: */
191: public ComplexTypeDerivationsReader() {
192:
193: }
194:
195: /**
196: * graph for CT Derivations view
197: *
198: */
199:
200: @SuppressWarnings("unchecked")
201: public Graph loadComplexTypeDerivationsGraph(
202: GlobalComplexType baseCT) {
203: // TODO implement interrupt when implementing project scope scanning
204: if (baseCT == null) {
205: StatusDisplayer.getDefault().setStatusText(""); //NOI18N
206: ErrorManager.getDefault().log(
207: "WhereUsedReader.loadComplexTypeDerivationsGraph()"
208: + " found null query base CT"); //NOI18N
209: return null;
210: }
211: // not used yet
212: int fileGroupNumber = 0;
213: // tally restrictions and extensions for the status message
214: List<Integer> derivationsCount = new ArrayList<Integer>();
215: derivationsCount.add(Integer.valueOf(0)); // extensions
216: derivationsCount.add(Integer.valueOf(0)); // restrictions
217: Graph graph = new Graph(true); // isDirected
218: graph.getNodeTable().addColumns(FIND_USAGES_NODES_SCHEMA);
219: graph.getEdgeTable().addColumns(FIND_USAGES_EDGES_SCHEMA);
220:
221: List<Component> componentsInGraph = new ArrayList<Component>();
222:
223: org.openide.nodes.Node displayNode = null;
224:
225: Named ref = baseCT;
226: // FindUsageResult result = RefactoringManager.getInstance().findUsages(baseCT,
227: // baseCT.getModel().getSchema());
228: Collection<RefactoringElement> elements = SharedUtils
229: .findUsages(baseCT, baseCT.getModel().getSchema());
230:
231: // UIHelper queryUIHelper = getUIHelper(baseCT);
232:
233: ArrayList<TreeElement> nodes = new ArrayList<TreeElement>();
234: for (RefactoringElement element : elements) {
235: TreeElement previewNode = TreeElementFactory
236: .getTreeElement(element);
237: if (previewNode != null)
238: nodes.add(previewNode);
239: }
240:
241: Node queryNode = createQueryNode(graph, baseCT, false,
242: componentsInGraph, false, fileGroupNumber);
243:
244: SchemaUIHelper uiHelper = new SchemaUIHelper();
245: displayNode = uiHelper.getDisplayNode(baseCT);
246:
247: queryNode.set(AnalysisConstants.COMPONENT_TYPE_NAME,
248: displayNode.getShortDescription()); // comp type
249: queryNode.set(AnalysisConstants.XAM_COMPONENT, baseCT);
250: queryNode.setString(AnalysisConstants.LABEL, displayNode
251: .getName());
252: queryNode.setString(AnalysisConstants.ELEMENT_TYPE, displayNode
253: .getDisplayName()); // element type
254:
255: loadGraph(true, //derivations of CTs only
256: graph, queryNode, baseCT, nodes, false, //is primitive
257: derivationsCount);
258: // Map of SourceGroups and their packages
259: /* Map<SourceGroup, Map<FileObject,Set<UsageGroup>>> sortedUses =
260: usageSet.getSortedUsages();
261: Set<Entry<SourceGroup,Map<FileObject,Set<UsageGroup>>>> sgUses =
262: sortedUses.entrySet();
263: int usagesCount = 0;
264: for (Entry<SourceGroup, Map<FileObject, Set<UsageGroup>>> sgUse:sgUses){
265: Set<Entry<FileObject,Set<UsageGroup>>> pkgUses = sgUse.getValue().entrySet();
266: for (Entry<FileObject, Set<UsageGroup>> pkgUse:pkgUses){
267: Set<UsageGroup> usages = pkgUse.getValue();
268: for (UsageGroup usage:usages){
269: int count = usage.getItems().size();
270: if (count < 1){
271: continue;
272: }
273: usagesCount += count;
274: fileGroupNumber++;
275: addUsagesToGraph(true, // derivations of CTs only
276: usage,
277: graph,
278: false, // is primitive
279: componentsInGraph,
280: baseCT.getModel(),
281: baseCT,
282: queryNode,
283: fileGroupNumber,
284: derivationsCount);
285:
286: }
287: }
288: }*/
289:
290: writeDerivationsFoundStatusMessage(derivationsCount.get(0)
291: .intValue(), derivationsCount.get(1).intValue(), baseCT);
292: return graph;
293: }
294:
295: private void writeDerivationsFoundStatusMessage(
296: final int extensionCount, final int restrictionCount,
297: GlobalComplexType baseCT) throws MissingResourceException {
298: if (baseCT == null) {
299: ErrorManager.getDefault().log(
300: "WhereUsedReader.loadComplexTypeDerivationsGraph()"
301: + " found null query base CT"); //NOI18N
302: }
303:
304: String extensionMsg = null;
305: if (extensionCount == 1) {
306: extensionMsg = NbBundle.getMessage(
307: ComplexTypeDerivationsReader.class,
308: "LBL_Found_1_Extension");
309: } else {
310: extensionMsg = MessageFormat.format(NbBundle.getMessage(
311: ComplexTypeDerivationsReader.class,
312: "LBL_Found_Extensions"),
313: new Object[] { extensionCount });
314: }
315:
316: String restrictionMsg = null;
317: if (restrictionCount == 1) {
318: restrictionMsg = MessageFormat.format(NbBundle.getMessage(
319: ComplexTypeDerivationsReader.class,
320: "LBL_1_Restriction_On_Complex_Type"),
321: new Object[] { baseCT.getName() });
322: } else {
323: restrictionMsg = MessageFormat.format(NbBundle.getMessage(
324: ComplexTypeDerivationsReader.class,
325: "LBL_Restrictions_On_Complex_Type"), new Object[] {
326: restrictionCount, baseCT.getName() });
327: }
328: if (!(extensionMsg == null || restrictionMsg == null)) {
329: StatusDisplayer.getDefault().setStatusText(
330: extensionMsg + restrictionMsg);
331:
332: }
333: }
334:
335: /* private UIHelper getUIHelper(Referenceable ref) {
336: return RefactoringManager.getInstance().getTargetComponentUIHelper(ref);
337: }*/
338:
339: /**
340: *
341: * Get usages in one schema file
342: * For CT Derivations query and Primitive Usages query
343: * @param usage collection of Items found in one model
344: * @param graph the prefuse Graph
345: * @param schema the schema being scanned, not necessarily the MV schema file
346: * @param ref the query component
347: * @param isPrimitive is the query component a primitive type
348: * @param componentsInGraph the list of SchemaComponents that are already in the graph
349: * @param model the Model of this Multiview's schema file
350: *
351: */
352: /*private void addUsagesToGraph(boolean ctDerivationsOnly,
353: UsageGroup usage,
354: Graph graph,
355: boolean isPrimitive,
356: List<Component> componentsInGraph,
357: Model model,
358: Component queryComponent,
359: Node queryNode,
360: int fileGroupNumber,
361: List<Integer> derivationsCount) {
362:
363: // Map<Component, List<Component>> um =
364: Collection<Usage> items = usage.getItems();
365: UIHelper uiHelper = usage.getEngine().getUIHelper();
366:
367: // *****************************
368: // *** FILE NODE
369: // *****************************
370:
371: // create a special edge from the file node to the query node
372: // that will be visible when the file node is collapsed
373: // This edge uses the default prefuse renderer, e.g.,
374: // a small solid arrow head
375: // When the file node is expanded, this edge will be
376: // hidden. See FindUsagesFocusControl (double click)
377: // Edge fileEdge = graph.addEdge(fileNode,queryNode);
378: // fileEdge.setString(AnalysisConstants.EDGE_TYPE,
379: // AnalysisConstants.FILE_EDGE_TYPE);
380: // fileEdge.setInt(AnalysisConstants.FILE_GROUP,
381: // fileGroupNumber);
382: Node fileNode = null;
383: for (Usage item:items){
384: if (ctDerivationsOnly){
385: Component usageComponent = item.getComponent();
386: if (usageComponent instanceof ComplexContentRestriction){
387: derivationsCount.set(1,derivationsCount.get(1)+1);
388: } else if (usageComponent instanceof ComplexExtension){
389: derivationsCount.set(0,derivationsCount.get(0)+1);
390: } else{
391: continue; // continue to next Item
392: }
393: }
394: // create file node and attach it to the query node
395: if (fileNode == null){
396: fileNode = createFileNode(graph,
397: queryComponent,
398: (FileObject)usage.getModel().getModelSource().getLookup().lookup(FileObject.class),
399: queryNode,
400: fileGroupNumber);
401: }
402: List<Component> aPath = uiHelper.getRelevantPathFromRoot(item);
403: Node parent = null;
404: for (int i = 0; i < aPath.size();i++){
405: Component sc = aPath.get(i);
406: Node pn = null;
407: AnalysisUtilities.ToolTipLine topLine = null;
408:
409: if (componentsInGraph.contains(sc)){
410: // there's already a Node for this Component,
411: // find it in Graph
412: pn = findDup(graph, sc);
413: assert pn != null:"Cannot find Node for Component "
414: +
415: sc; //NOI18N
416: }
417:
418: if (pn == null){
419: pn = createNode(graph,
420: sc,
421: uiHelper,
422: false,
423: componentsInGraph,
424: queryComponent,
425: fileGroupNumber);
426: }
427:
428: if (i == 0){
429: // connect top node to file node
430: AnalysisUtilities.ToolTipLine typeLine =
431: new AnalysisUtilities.ToolTipLine(pn.getString(AnalysisConstants.COMPONENT_TYPE_NAME),
432: 100,
433: Color.BLACK.getRGB(),
434: AnalysisUtilities.ToolTipLine.
435: HorizontalAlignment.CENTER);
436: String toolTip = AnalysisUtilities.createHTMLToolTip(
437: new AnalysisUtilities.ToolTipLine[] {topLine, typeLine});
438: pn.setString(AnalysisConstants.TOOLTIP, toolTip);
439:
440: // connect the node to the File Node with compositon edge
441: Edge fileCompositionEdge = graph.addEdge(pn,fileNode);
442: fileCompositionEdge.setString(AnalysisConstants.EDGE_TYPE,
443: AnalysisConstants.COMPOSITION);
444: // it's part of the group of nodes and edges that are
445: // visible or hidden, depending on whether the file node
446: // is expanded or collapsed
447: fileCompositionEdge.setInt(AnalysisConstants.FILE_GROUP,
448: fileGroupNumber);
449:
450: // set the new parent node
451: parent = pn;
452: } else {
453:
454: AnalysisUtilities.ToolTipLine typeLine =
455: new AnalysisUtilities.ToolTipLine(getCompTypeDisplayName(pn),
456: 100,
457: Color.BLACK.getRGB(),
458: AnalysisUtilities.ToolTipLine.
459: HorizontalAlignment.CENTER);
460: String toolTip = AnalysisUtilities.createHTMLToolTip(
461: new AnalysisUtilities.ToolTipLine[] {topLine, typeLine});
462: pn.setString(AnalysisConstants.TOOLTIP, toolTip);
463:
464:
465: // connect it to its parent (parent should not be null)
466: if (parent != null){
467: addCompositionEdge(graph,
468: pn,
469: parent,
470: fileGroupNumber);
471: }
472: parent = pn;
473: }
474:
475:
476: // Usage node is last
477: if (i == aPath.size()-1){
478: // this is the usage node
479: pn.setBoolean(
480: AnalysisConstants.IS_USAGE_NODE, true);
481:
482: topLine = new AnalysisUtilities.ToolTipLine((
483: MessageFormat.format(NbBundle.getMessage(
484: ComplexTypeDerivationsReader.class, "LBL_Uses_Component"),
485: new Object[] {queryNode.getString(
486: AnalysisConstants.LABEL) })),
487: 100,
488: Color.BLACK.getRGB(),
489: AnalysisUtilities.ToolTipLine.
490: HorizontalAlignment.CENTER);
491: // Connect this usage node to the Query Node
492: // with the appropriate edge (composition or reference)
493: addApppropriateEdge(graph,
494: pn,
495: queryNode,
496: fileGroupNumber,
497: item.getType());
498:
499: }// END if (i == aPath.size()-1)
500:
501: }
502: }
503: }// end addUsagesToGraph()*/
504:
505: private static String getCompTypeDisplayName(final Node pn)
506: throws MissingResourceException {
507: String compType = null;
508: if (pn.canGetBoolean(AnalysisConstants.IS_PRIMITIVE)
509: && pn.getBoolean(AnalysisConstants.IS_PRIMITIVE)) {
510: compType = NbBundle.getMessage(
511: ComplexTypeDerivationsReader.class,
512: "LBL_Primitive_Type");
513: } else {
514: compType = pn
515: .getString(AnalysisConstants.COMPONENT_TYPE_NAME);
516: }
517: return compType;
518: }
519:
520: private void addCompositionEdge(Graph graph, Node part, Node whole,
521: int fileGroupNumber) {
522: Edge edge = graph.addEdge(part, whole);
523: //edge.setBoolean(AnalysisConstants.SHOW, isVisible);
524: edge.setString(AnalysisConstants.EDGE_TYPE,
525: AnalysisConstants.COMPOSITION);
526: edge.setInt(AnalysisConstants.FILE_GROUP, Integer
527: .valueOf(fileGroupNumber));
528:
529: }
530:
531: /**
532: * Adds a Reference edge or Generalization edge from
533: * "from" node to the queryNode
534: *
535: *
536: */
537: private void addApppropriateEdge(Graph graph, Node from,
538: Node queryNode, int fileGroupNumber, Type edgeType) {
539: Edge edge = graph.addEdge(from, queryNode);
540: // edge.setBoolean(AnalysisConstants.SHOW, isVisible);
541:
542: edge.setInt(AnalysisConstants.FILE_GROUP, Integer
543: .valueOf(fileGroupNumber));
544: if (edgeType == Type.GENERALIZATION) {
545: edge.setString(AnalysisConstants.EDGE_TYPE,
546: AnalysisConstants.GENERALIZATION);
547: } else if (edgeType == Type.REFERENCE) {
548: edge.setString(AnalysisConstants.EDGE_TYPE,
549: AnalysisConstants.REFERENCE);
550: from
551: .setString(
552: AnalysisConstants.LABEL,
553: MessageFormat
554: .format(
555: NbBundle
556: .getMessage(
557: ComplexTypeDerivationsReader.class,
558: "LBL_References_Ref"),
559: new Object[] { queryNode
560: .getString(AnalysisConstants.LABEL) }));
561: }
562: }
563:
564: private Node findDup(Graph graph, Object sc) {
565: Iterator it = graph.nodes();
566: while (it.hasNext()) {
567: Node n = Node.class.cast(it.next());
568: Object nodeSC = n.get(AnalysisConstants.XAM_COMPONENT);
569: if ((n.canGetBoolean(AnalysisConstants.IS_FILE_NODE) && n
570: .getBoolean(AnalysisConstants.IS_FILE_NODE) == false)
571: && nodeSC != null) {
572: if (nodeSC == sc) {
573: return n;
574: }
575: }
576: }
577: return null;
578: }
579:
580: public static Node createQueryNode(Graph graph, Component query,
581: boolean isPrimitive, List componentsInGraph,
582: boolean showOnlyDerivations, int fileGroupNumber) {
583: // TODO remove this temporary hack when UIHelper for query Component is available
584: Node queryNode = null;
585: String name = ""; //NOI18N
586: if (query instanceof Named) {
587: name = ((Named) Named.class.cast(query)).getName();
588: }
589: queryNode = graph.addNode();
590: componentsInGraph.add(query);
591: queryNode.setBoolean(AnalysisConstants.IS_PRIMITIVE,
592: isPrimitive);
593: queryNode.setString(AnalysisConstants.LABEL, name);
594: queryNode.setString(AnalysisConstants.COMPONENT_TYPE_NAME, ""); //NOI18N
595: queryNode.set(AnalysisConstants.XAM_COMPONENT, query);
596: queryNode.setInt(AnalysisConstants.FILE_GROUP, fileGroupNumber);
597:
598: queryNode.setBoolean(AnalysisConstants.IS_QUERY_NODE, true);
599: // unset the FILE_GROUP because this node is always visible
600: queryNode.setInt(AnalysisConstants.FILE_GROUP, -1);
601: // reset IS_PRIMITIVE in case it is
602: queryNode.setBoolean(AnalysisConstants.IS_PRIMITIVE,
603: isPrimitive);
604:
605: AnalysisUtilities.ToolTipLine topLine = new AnalysisUtilities.ToolTipLine(
606: (showOnlyDerivations ? NbBundle.getMessage(
607: ComplexTypeDerivationsReader.class,
608: "LBL_Base_Complex_Type") : NbBundle.getMessage(
609: ComplexTypeDerivationsReader.class,
610: "LBL_Query_Component")),
611: 100,
612: Color.BLACK.getRGB(),
613: AnalysisUtilities.ToolTipLine.HorizontalAlignment.CENTER);
614: String compType = getCompTypeDisplayName(queryNode);
615: AnalysisUtilities.ToolTipLine typeLine = new AnalysisUtilities.ToolTipLine(
616: compType,
617: 100,
618: Color.BLACK.getRGB(),
619: AnalysisUtilities.ToolTipLine.HorizontalAlignment.CENTER);
620: String toolTip = AnalysisUtilities
621: .createHTMLToolTip(new AnalysisUtilities.ToolTipLine[] {
622: topLine, typeLine });
623:
624: queryNode.setString(AnalysisConstants.TOOLTIP, toolTip);
625: return queryNode;
626: }
627:
628: private Node createFileNode(Graph graph, Component queryComp,
629: FileObject fobj, Node queryNode, int fileGroupNumber) {
630: if (queryComp == null || fobj == null) {
631: return null;
632: }
633: String fileType = SharedUtils.getXmlFileType(fobj);
634: Node n = graph.addNode();
635: n.setString(AnalysisConstants.FILE_TYPE, fileType);
636: n.setInt(AnalysisConstants.FILE_NODE_FILE_GROUP,
637: fileGroupNumber);
638: n.setBoolean(AnalysisConstants.IS_EXPANDED, false);
639: n.setBoolean(AnalysisConstants.IS_FILE_NODE, true);
640: n.set(AnalysisConstants.JAVA_AWT_IMAGE, SharedUtils
641: .getImage(fobj));
642: n.setString(AnalysisConstants.LABEL, fobj.getNameExt());
643: n.setString(AnalysisConstants.XML_FILENAME, fobj.getNameExt());
644: n.set(AnalysisConstants.FILE_OBJECT, fobj);
645:
646: // "Schema file containing usages of XYZ"
647: AnalysisUtilities.ToolTipLine topLine = new AnalysisUtilities.ToolTipLine(
648: MessageFormat
649: .format(
650: NbBundle
651: .getMessage(
652: ComplexTypeDerivationsReader.class,
653: "LBL_Xml_File_With_Usages"),
654: new Object[] {
655: SharedUtils
656: .getXmlFileTypeDisplayName(fileType),
657: queryNode
658: .getString(AnalysisConstants.LABEL) }),
659: 100,
660: Color.BLACK.getRGB(),
661: AnalysisUtilities.ToolTipLine.HorizontalAlignment.CENTER);
662: AnalysisUtilities.ToolTipLine typeLine = new AnalysisUtilities.ToolTipLine(
663: FileUtil.getFileDisplayName(fobj),
664: 100,
665: Color.BLACK.getRGB(),
666: AnalysisUtilities.ToolTipLine.HorizontalAlignment.CENTER);
667: String toolTip = AnalysisUtilities
668: .createHTMLToolTip(new AnalysisUtilities.ToolTipLine[] {
669: topLine, typeLine });
670:
671: n.setString(AnalysisConstants.TOOLTIP, toolTip);
672: return n;
673: }
674:
675: /**
676: *
677: *
678: */
679: public static Node createNode(Graph graph, TreeElement displayNode,
680: boolean isPrimitive, List componentsInGraph,
681: Component queryComponent, int fileGroupNumber) {
682: Node n = graph.addNode();
683:
684: if (componentsInGraph != null) {
685: componentsInGraph.add(displayNode.getUserObject());
686: }
687: // DisplayInfo dInfo = div.getDisplayInfo(comp);
688: // org.openide.nodes.Node displayNode = uiHelper.getDisplayNode(comp);
689:
690: // if the queryComponent node is a primitive,
691: // check if the usage node is also a primitive, i.e.,
692: // from the same model (the W3c Schema model)
693: if (isPrimitive) {
694: if (displayNode.getUserObject() instanceof Component) {
695: Component comp = (Component) displayNode
696: .getUserObject();
697: if (comp.getModel() == queryComponent.getModel()) {
698: n.setBoolean(AnalysisConstants.IS_PRIMITIVE, true);
699: }
700: }
701: }
702: n.setBoolean(AnalysisConstants.IS_PRIMITIVE, false);
703: n.setString(AnalysisConstants.LABEL, displayNode.getText(true));
704: n.setString(AnalysisConstants.COMPONENT_TYPE_NAME, displayNode
705: .getText(true));
706:
707: if (displayNode.getUserObject() instanceof Component)
708: n.set(AnalysisConstants.XAM_COMPONENT,
709: (Component) displayNode.getUserObject());
710: else if (displayNode.getUserObject() instanceof RefactoringElement) {
711: Component comp = (Component) ((RefactoringElement) displayNode
712: .getUserObject()).getLookup().lookup(
713: Component.class);
714: n.set(AnalysisConstants.XAM_COMPONENT, comp);
715: } else
716: //no clue what kind of obj we got
717: n.set(AnalysisConstants.XAM_COMPONENT, null);
718:
719: //We no longer have a ide Node to represent the usage component
720: //n.set(AnalysisConstants.OPENIDE_NODE, displayNode );
721: n.setInt(AnalysisConstants.FILE_GROUP, fileGroupNumber);
722: n.set(AnalysisConstants.JAVA_AWT_IMAGE,
723: ((ImageIcon) displayNode.getIcon()).getImage());
724:
725: return n;
726: }
727:
728: public void loadGraph(boolean ctDerivationsOnly, Graph graph,
729: Node queryNode, Component queryComponent,
730: ArrayList<TreeElement> elements, boolean isPrimitive,
731: List<Integer> derivationsCount) {
732: List componentsInGraph = new ArrayList();
733: List<FileObject> files = new ArrayList<FileObject>();
734: Map<FileObject, Node> fileNodes = new Hashtable<FileObject, Node>();
735: int fileGroupNumber = 0;
736: int usagesCount = 0;
737:
738: // *****************************
739: // *** FILE NODE
740: // *****************************
741: // create file node and attach it to the query node
742: for (int i = 0; i < elements.size(); i++) {
743:
744: TreeElement usageNode = elements.get(i);
745:
746: //get the RefactoringElement
747: RefactoringElement usageElement = (RefactoringElement) usageNode
748: .getUserObject();
749:
750: if (ctDerivationsOnly) {
751: Component usageComponent = usageElement.getLookup()
752: .lookup(Component.class);
753: if (usageComponent instanceof ComplexContentRestriction) {
754: derivationsCount
755: .set(1, derivationsCount.get(1) + 1);
756: } else if (usageComponent instanceof ComplexExtension) {
757: derivationsCount
758: .set(0, derivationsCount.get(0) + 1);
759: } else {
760: continue; // continue to next Item
761: }
762: }
763: //Next, lets create a file node and attach it to the query node
764: //there should be one file node per file object
765:
766: FileObject fo = usageElement.getParentFile();
767: Node parent = null;
768: if (!(files.contains(fo))) {
769: Node fileNode = createFileNode(graph, queryComponent,
770: fo, queryNode, ++fileGroupNumber);
771: parent = fileNode;
772: fileNodes.put(fo, fileNode);
773: } else {
774: parent = fileNodes.get(fo);
775: }
776:
777: Node child = null;
778: TreeElement leaf = usageNode;
779:
780: while ((leaf.getParent(true)) instanceof TreeElement) {
781: Node pn = null;
782:
783: Object userObject = leaf.getUserObject();
784:
785: //we dont want to draw grap beyond the file
786: if ((userObject instanceof FileObject)) {
787: break;
788: }
789:
790: if (componentsInGraph.contains(userObject)) {
791: //there's already a node for this
792: pn = findDup(graph, userObject);
793: assert pn != null : "Cannot find node for User Object"
794: + userObject;
795: }
796:
797: if (pn == null) {
798: pn = createNode(graph, leaf, isPrimitive,
799: componentsInGraph, queryComponent,
800: fileGroupNumber);
801:
802: }
803:
804: //// To find out if this tree element is a usage node, we would need to check if there's a corresponding
805: //// refactoring element. only leaf nodes have corresponding refactoring elements
806: AnalysisUtilities.ToolTipLine topLine = null;
807: if (userObject instanceof RefactoringElement) {
808: pn
809: .setBoolean(
810: AnalysisConstants.IS_USAGE_NODE,
811: true);
812: topLine = new AnalysisUtilities.ToolTipLine(
813: (MessageFormat
814: .format(
815: NbBundle
816: .getMessage(
817: ComplexTypeDerivationsReader.class,
818: "LBL_Uses_Component"),
819: new Object[] { queryNode
820: .getString(AnalysisConstants.LABEL) })),
821: 100,
822: Color.BLACK.getRGB(),
823: AnalysisUtilities.ToolTipLine.HorizontalAlignment.CENTER);
824:
825: // Connect this usage node to the Query Node
826: // with the appropriate edge (composition or reference)
827: Component obj = ((RefactoringElement) userObject)
828: .getLookup().lookup(Component.class);
829: if (obj != null)
830: addApppropriateEdge(graph, pn, queryNode,
831: fileGroupNumber, Type.REFERENCE);
832: else
833: addApppropriateEdge(graph, pn, queryNode,
834: fileGroupNumber, null);
835:
836: child = pn;
837: leaf = leaf.getParent(true);
838: continue;
839: }
840:
841: AnalysisUtilities.ToolTipLine typeLine = new AnalysisUtilities.ToolTipLine(
842: getCompTypeDisplayName(pn),
843: 100,
844: Color.BLACK.getRGB(),
845: AnalysisUtilities.ToolTipLine.HorizontalAlignment.CENTER);
846: String toolTip = AnalysisUtilities
847: .createHTMLToolTip(new AnalysisUtilities.ToolTipLine[] {
848: topLine, typeLine });
849: pn.setString(AnalysisConstants.TOOLTIP, toolTip);
850:
851: // connect it to its parent
852: addCompositionEdge(graph, child, pn, fileGroupNumber);
853: child = pn;
854: leaf = leaf.getParent(true);
855: }
856:
857: AnalysisUtilities.ToolTipLine topLine = null;
858: // connect last node to file node
859: AnalysisUtilities.ToolTipLine typeLine = new AnalysisUtilities.ToolTipLine(
860: child
861: .getString(AnalysisConstants.COMPONENT_TYPE_NAME),
862: 100,
863: Color.BLACK.getRGB(),
864: AnalysisUtilities.ToolTipLine.HorizontalAlignment.CENTER);
865: String toolTip = AnalysisUtilities
866: .createHTMLToolTip(new AnalysisUtilities.ToolTipLine[] {
867: topLine, typeLine });
868: child.setString(AnalysisConstants.TOOLTIP, toolTip);
869:
870: // connect the node to the File Node with compositon edge
871: Edge fileCompositionEdge = graph.addEdge(child, parent);
872: fileCompositionEdge.setString(AnalysisConstants.EDGE_TYPE,
873: AnalysisConstants.COMPOSITION);
874: // it's part of the group of nodes and edges that are
875: // visible or hidden, depending on whether the file node
876: // is expanded or collapsed
877: fileCompositionEdge.setInt(AnalysisConstants.FILE_GROUP,
878: fileGroupNumber);
879:
880: }
881:
882: }
883:
884: }
|