source: src/main/java/weka/gui/treevisualizer/TreeBuild.java @ 22

Last change on this file since 22 was 4, checked in by gnappo, 14 years ago

Import di weka.

File size: 19.0 KB
Line 
1/*
2 *    This program is free software; you can redistribute it and/or modify
3 *    it under the terms of the GNU General Public License as published by
4 *    the Free Software Foundation; either version 2 of the License, or
5 *    (at your option) any later version.
6 *
7 *    This program is distributed in the hope that it will be useful,
8 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 *    GNU General Public License for more details.
11 *
12 *    You should have received a copy of the GNU General Public License
13 *    along with this program; if not, write to the Free Software
14 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 */
16
17/*
18 *    Tree_build.java
19 *    Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.gui.treevisualizer;
24
25import java.util.*;
26import java.io.*;
27import java.awt.*;
28
29/**
30 * This class will parse a dotty file and construct a tree structure from it
31 * with Edge's and Node's
32 *
33 * @author Malcolm Ware (mfw4@cs.waikato.ac.nz)
34 * @version $Revision: 1.4 $
35 */
36public class TreeBuild {
37  //this class will parse the tree into relevant strings
38  //into info objects
39  //from there it will create the nodes and edges from the info objects
40
41  /** The name of the tree, Not in use. */
42  private String m_graphName;
43
44  /** An array with all the nodes initially constructed into it. */
45  private Vector m_aNodes;
46
47  /** An array with all the edges initially constructed into it. */
48  private Vector m_aEdges;
49
50  /** An array containing a structure that describes the node without
51   * actually creating it. */
52  private Vector m_nodes;
53
54  /** An arry containing a structure that describes the edge without
55   * actually creating it. */
56  private Vector m_edges;
57
58  /** An object setup to take graph data. */
59  private InfoObject m_grObj;
60
61  /** An object setup to take node data. */
62  private InfoObject m_noObj;
63
64  /** An object setup to take edge data. */
65  private InfoObject m_edObj;
66
67  /** true if it is a digraph. (note that this can't build digraphs). */
68  private boolean m_digraph;
69 
70  /** The stream to parse. */
71  private StreamTokenizer m_st;
72
73  /** A table containing all the colors. */
74  private Hashtable m_colorTable;
75 
76  /**
77   * Upon construction this will only setup the color table for quick
78   * reference of a color.
79   */
80  public TreeBuild() {
81    m_colorTable = new Hashtable();
82   
83    Colors ab = new Colors();
84    for (int noa = 0;noa < ab.m_cols.length;noa++) {
85      m_colorTable.put(ab.m_cols[noa].m_name,ab.m_cols[noa].m_col);
86    }
87  } 
88   
89  /**
90   * This will build A node structure from the dotty format passed. Don't
91   * send a dotty format with multiple parents
92   * per node, and ensure that there is 1 and only 1 node with no parent.
93   *
94   * @param t The reader with the dotty string to be read.
95   * @return The top node of the tree structure (the last node with no parent).
96   */
97  public Node create(Reader t) {
98    m_nodes = new Vector(50,50);
99    m_edges = new Vector(50,50);
100    m_grObj = new InfoObject("graph");
101    m_noObj = new InfoObject("node");
102    m_edObj = new InfoObject("edge");
103    m_digraph = false;
104   
105    m_st = new StreamTokenizer(new BufferedReader(t));
106    setSyntax();
107
108    graph();
109
110    Node top = generateStructures();
111   
112    return top;
113  }
114 
115  /**
116   * This will go through all the found Nodes and Edges build instances of
117   * these
118   * and link them together.
119   *
120   * @return The node with no parent (the top of the tree).
121   */
122  private Node generateStructures() {
123    String id,label,source,target;
124    Integer shape,style;
125    int fontsize;
126    Color fontcolor,color;
127
128    InfoObject t;
129    m_aNodes = new Vector(50,50);
130    m_aEdges = new Vector(50,50);
131    for (int noa = 0;noa < m_nodes.size();noa++) {
132      t = (InfoObject)m_nodes.elementAt(noa);
133      id = t.m_id;
134     
135      if (t.m_label == null) {
136        if (m_noObj.m_label == null) {
137          label = "";
138        }
139        else {
140          label = m_noObj.m_label;
141        }
142      }
143      else {
144        label = t.m_label;
145      }
146     
147      if (t.m_shape == null) {
148        if (m_noObj.m_shape == null) {
149          shape = new Integer(2);
150        }
151        else {
152          shape = getShape(m_noObj.m_shape);
153        }
154      }
155      else {
156        shape = getShape(t.m_shape);
157      }
158      if (shape == null) {
159        shape = new Integer(2);
160      }
161     
162      if (t.m_style == null) {
163        if (m_noObj.m_style == null) {
164          style = new Integer(1);
165        }
166        else {
167          style = getStyle(m_noObj.m_style);
168        }
169      }
170      else {
171        style = getStyle(t.m_style);
172      }
173      if (style == null) {
174        style = new Integer(1);
175      }
176     
177      if (t.m_fontSize == null) {
178        if (m_noObj.m_fontSize == null) {
179          fontsize = 12;
180        }
181        else {
182          fontsize = Integer.valueOf(m_noObj.m_fontSize).intValue();
183        }
184      }
185      else {
186        fontsize = Integer.valueOf(t.m_fontSize).intValue();
187      }
188     
189      if (t.m_fontColor == null) {
190        if (m_noObj.m_fontColor == null) {
191          fontcolor = Color.black;
192        }
193        else {
194          fontcolor = (Color)m_colorTable
195            .get(m_noObj.m_fontColor.toLowerCase());
196        }
197      }
198      else {
199        fontcolor = (Color)m_colorTable.get(t.m_fontColor.toLowerCase());
200      }
201      if (fontcolor == null) {
202        fontcolor = Color.black;
203      }
204     
205      if (t.m_color == null) {
206        if (m_noObj.m_color == null) {
207          color = Color.gray;
208        }
209        else {
210          color = (Color)m_colorTable.get(m_noObj.m_color.toLowerCase());
211        }
212      }
213      else {
214        color = (Color)m_colorTable.get(t.m_color.toLowerCase());
215      }
216      if (color == null) {
217        color = Color.gray;
218      }
219     
220      m_aNodes.addElement(new Node(label,id,style.intValue(),shape.intValue(),
221                                  color,t.m_data));
222    }
223
224
225    for (int noa = 0;noa < m_edges.size();noa++) {
226      t = (InfoObject)m_edges.elementAt(noa);
227      id = t.m_id;
228     
229      if (t.m_label == null) {
230        if (m_noObj.m_label == null) {
231          label = "";
232        }
233        else {
234          label = m_noObj.m_label;
235        }
236      }
237      else {
238        label = t.m_label;
239      }
240     
241      if (t.m_shape == null) {
242        if (m_noObj.m_shape == null) {
243          shape = new Integer(2);
244        }
245        else {
246          shape = getShape(m_noObj.m_shape);
247        }
248      }
249      else {
250        shape = getShape(t.m_shape);
251      }
252      if (shape == null) {
253        shape = new Integer(2);
254      }
255     
256      if (t.m_style == null) {
257        if (m_noObj.m_style == null) {
258          style = new Integer(1);
259        }
260        else {
261          style = getStyle(m_noObj.m_style);
262        }
263      }
264      else {
265        style = getStyle(t.m_style);
266      }
267      if (style == null) {
268        style = new Integer(1);
269      }
270     
271      if (t.m_fontSize == null) {
272        if (m_noObj.m_fontSize == null) {
273          fontsize = 12;
274        }
275        else {
276          fontsize = Integer.valueOf(m_noObj.m_fontSize).intValue();
277        }
278      }
279      else {
280        fontsize = Integer.valueOf(t.m_fontSize).intValue();
281      }
282     
283      if (t.m_fontColor == null) {
284        if (m_noObj.m_fontColor == null) {
285          fontcolor = Color.black;
286        }
287        else {
288          fontcolor = (Color)m_colorTable
289            .get(m_noObj.m_fontColor.toLowerCase());
290        }
291      }
292      else {
293        fontcolor = (Color)m_colorTable.get(t.m_fontColor.toLowerCase());
294      }
295      if (fontcolor == null) {
296        fontcolor = Color.black;
297      }
298     
299      if (t.m_color == null) {
300        if (m_noObj.m_color == null) {
301          color = Color.white;
302        }
303        else {
304          color = (Color)m_colorTable.get(m_noObj.m_color.toLowerCase());
305        }
306      }
307      else {
308        color = (Color)m_colorTable.get(t.m_color.toLowerCase());
309      }
310      if (color == null) {
311        color = Color.white;
312      }
313     
314      m_aEdges.addElement(new Edge(label,t.m_source,t.m_target));
315    }
316       
317    boolean f_set,s_set;
318    Node x,sour = null,targ = null;
319    Edge y;
320    for (int noa = 0;noa < m_aEdges.size();noa++) {
321      f_set = false;
322      s_set = false;
323      y = (Edge)m_aEdges.elementAt(noa);
324      for (int nob = 0;nob < m_aNodes.size();nob++) {
325        x = (Node)m_aNodes.elementAt(nob);
326        if (x.getRefer().equals(y.getRtarget())) {
327          f_set = true;
328          targ = x;
329        }
330        if (x.getRefer().equals(y.getRsource())) {
331          s_set = true;
332          sour = x;
333        }
334        if (f_set == true && s_set == true) {
335          break;
336        }
337      }
338      if (targ != sour) {
339        y.setTarget(targ);
340        y.setSource(sour);
341      }
342      else {
343        System.out.println("logic error");
344      }
345    }
346   
347    for (int noa = 0;noa < m_aNodes.size();noa++) {
348      if (((Node)m_aNodes.elementAt(noa)).getParent(0) == null) {
349        sour = (Node)m_aNodes.elementAt(noa);
350      }
351    }
352
353    return sour;
354  }
355 
356  /**
357   * This will convert the shape string to an int representing that shape.
358   *
359   * @param sh The name of the shape.
360   * @return An Integer representing the shape.
361   */
362  private Integer getShape(String sh) {
363    if (sh.equalsIgnoreCase("box") || sh.equalsIgnoreCase("rectangle")) {
364      return new Integer(1);
365    }
366    else if (sh.equalsIgnoreCase("oval")) {
367      return new Integer(2);
368    }
369    else if (sh.equalsIgnoreCase("diamond")) {
370      return new Integer(3);
371    }
372    else {
373      return null;
374    }
375  }
376 
377  /**
378   * Converts the string representing the fill style int oa number
379   * representing it.
380   *
381   * @param sty The name of the style.
382   * @return An Integer representing the shape.
383   */
384  private Integer getStyle(String sty) {
385    if (sty.equalsIgnoreCase("filled")) {
386      return new Integer(1);
387    }
388    else {
389      return null;
390    }
391  }
392
393  /**
394   * This will setup the syntax for the tokenizer so that it parses the
395   * string properly.
396   *
397   */
398  private void setSyntax() {
399    m_st.resetSyntax();
400    m_st.eolIsSignificant(false);
401    m_st.slashStarComments(true);
402    m_st.slashSlashComments(true);
403    //System.out.println("slash");
404    m_st.whitespaceChars(0,' ');
405    m_st.wordChars(' '+1,'\u00ff');
406    m_st.ordinaryChar('[');
407    m_st.ordinaryChar(']');
408    m_st.ordinaryChar('{');
409    m_st.ordinaryChar('}');
410    m_st.ordinaryChar('-');
411    m_st.ordinaryChar('>');
412    m_st.ordinaryChar('/');
413    m_st.ordinaryChar('*');
414    m_st.quoteChar('"');
415    m_st.whitespaceChars(';',';');
416    m_st.ordinaryChar('=');
417  }
418
419  /**
420   * This is the alternative syntax for the tokenizer.
421   */
422  private void alterSyntax() {
423    m_st.resetSyntax();
424    m_st.wordChars('\u0000', '\u00ff');
425    m_st.slashStarComments(false);
426    m_st.slashSlashComments(false);
427    m_st.ordinaryChar('\n');
428    m_st.ordinaryChar('\r');
429  }
430
431  /**
432   * This will parse the next token out of the stream and check for certain
433   * conditions.
434   *
435   * @param r The error string to print out if something goes wrong.
436   */
437  private void nextToken(String r) {
438    int t = 0;
439    try {
440      t = m_st.nextToken();
441    } catch(IOException e) {
442    }
443   
444    if (t == m_st.TT_EOF) {
445      System.out.println("eof , " + r);
446    }
447    else if (t == m_st.TT_NUMBER) {
448      System.out.println("got a number , " + r);
449    }
450  }
451 
452  /**
453   * Parses the top of the dotty stream that has the graph information.
454   *
455   */
456  private void graph() {
457    boolean flag = true;
458    String s;
459    //expect digraph
460    int t;
461    nextToken("expected 'digraph'");
462   
463    if (m_st.sval.equalsIgnoreCase("digraph")) {
464      m_digraph = true;
465    }
466    else {
467      System.out.println("expected 'digraph'");
468    }
469   
470    nextToken("expected a Graph Name");
471    if (m_st.sval != null) {
472      m_graphName = m_st.sval;
473    }
474    else {
475      System.out.println("expected a Graph Name");
476    }
477   
478    nextToken("expected '{'");
479   
480    if (m_st.ttype == '{') {
481      stmtList();
482    }
483    else {
484      System.out.println("expected '{'");
485    }
486  }
487
488  /**
489   * This is one of the states, this one is where new items can be defined
490   * or the structure can end.
491   *
492   */
493  private void stmtList() {
494    boolean flag = true;
495    String s;
496    int t;
497    while(flag) {
498      nextToken("expects a STMT_LIST item or '}'");
499      if (m_st.ttype == '}') {
500        flag = false;
501      }
502      else if (m_st.sval.equalsIgnoreCase("graph") ||
503               m_st.sval.equalsIgnoreCase("node") ||
504               m_st.sval.equalsIgnoreCase("edge")) {
505        m_st.pushBack();
506        attrStmt();
507      }
508      else if (m_st.sval != null) {
509        nodeId(m_st.sval,0);
510      }
511      else {
512        System.out.println("expects a STMT_LIST item or '}'");
513      }
514    }
515  }
516
517  /**
518   * This will deal specifically with a new object such as graph , node , edge.
519   *
520   */
521  private void attrStmt() {
522   
523    nextToken("expected 'graph' or 'node' or 'edge'");
524   
525    if (m_st.sval.equalsIgnoreCase("graph")) {
526      nextToken("expected a '['");
527      if (m_st.ttype == '[') {
528        attrList(m_grObj);
529      }
530      else {
531        System.out.println("expected a '['");
532      }
533    }
534    else if (m_st.sval.equalsIgnoreCase("node")) {
535      nextToken("expected a '['");
536      if (m_st.ttype == '[') {
537        attrList(m_noObj);
538      }
539      else {
540        System.out.println("expected a '['");
541      }
542    }
543    else if (m_st.sval.equalsIgnoreCase("edge")) {
544      nextToken("expected a '['");
545      if (m_st.ttype == '[') {
546        attrList(m_edObj);
547      }
548      else {
549        System.out.println("expected a '['");
550      }
551     
552    }
553    else {
554      System.out.println("expected 'graph' or 'node' or 'edge'"); 
555    }
556  }
557
558  /**
559   * Generates a new InfoObject with the specified name and either does
560   * further processing if applicable
561   * Otherwise it is an edge and will deal with that.
562   *
563   * @param s The ID string.
564   * @param t Not sure!.
565   */
566  private void nodeId(String s,int t) {
567   
568    nextToken("error occurred in node_id");
569
570    if (m_st.ttype == '}') {
571      //creates a node if t is zero
572      if (t == 0) {
573        m_nodes.addElement(new InfoObject(s));
574      }
575      m_st.pushBack();
576    }
577    else if (m_st.ttype == '-') {
578      nextToken("error occurred checking for an edge");
579      if (m_st.ttype == '>') {
580        edgeStmt(s);
581      }
582      else {
583        System.out.println("error occurred checking for an edge");
584      }
585    }
586    else if (m_st.ttype == '[') {
587      //creates a node if t is zero and sends it to attr
588      if (t == 0) {
589        m_nodes.addElement(new InfoObject(s));
590        attrList((InfoObject)m_nodes.lastElement());
591      }
592      else {
593        attrList((InfoObject)m_edges.lastElement());
594      }
595    }
596    else if (m_st.sval != null) {
597      //creates a node if t is zero
598      if (t == 0) {
599        m_nodes.addElement(new InfoObject(s));
600      }
601      m_st.pushBack();
602    }
603    else {
604      System.out.println("error occurred in node_id");
605    }
606  }
607
608  /**
609   * This will get the target of the edge.
610   *
611   * @param i The source of the edge.
612   */
613  private void edgeStmt(String i) {
614    nextToken("error getting target of edge");
615   
616    if (m_st.sval != null) {
617      m_edges.addElement(new InfoObject("an edge ,no id"));
618      ((InfoObject)m_edges.lastElement()).m_source = i;
619      ((InfoObject)m_edges.lastElement()).m_target = m_st.sval;
620      nodeId(m_st.sval,1);
621    }
622    else {
623      System.out.println("error getting target of edge");
624    }
625  }
626
627  /**
628   * This will parse all the items in the attrib list for an object.
629   *
630   * @param a The object that the attribs apply to.
631   */
632  private void attrList(InfoObject a) {
633    boolean flag = true;
634   
635    while (flag) {
636      nextToken("error in attr_list");
637      //System.out.println(st.sval);
638      if (m_st.ttype == ']') {
639        flag = false;
640      }
641      else if (m_st.sval.equalsIgnoreCase("color")) {
642        nextToken("error getting color");
643        if (m_st.ttype == '=') {
644          nextToken("error getting color");
645          if (m_st.sval != null) {
646            a.m_color = m_st.sval;
647          }
648          else {
649            System.out.println("error getting color");
650          }
651        }
652        else {
653          System.out.println("error getting color");
654        }
655      }
656      else if (m_st.sval.equalsIgnoreCase("fontcolor")) {
657        nextToken("error getting font color");
658        if (m_st.ttype == '=') {
659          nextToken("error getting font color");
660          if (m_st.sval != null) {
661            a.m_fontColor = m_st.sval;
662          }
663          else {
664            System.out.println("error getting font color");
665          }
666        }
667        else {
668          System.out.println("error getting font color");
669        }
670      }
671      else if (m_st.sval.equalsIgnoreCase("fontsize")) {
672        nextToken("error getting font size");
673        if (m_st.ttype == '=') {
674          nextToken("error getting font size");
675          if (m_st.sval != null) {
676            a.m_fontSize = m_st.sval;
677          }
678          else {
679            System.out.println("error getting font size");
680          }
681        }
682        else {
683          System.out.println("error getting font size");
684        }
685      }
686      else if (m_st.sval.equalsIgnoreCase("label")) {
687        nextToken("error getting label");
688        if (m_st.ttype == '=') {
689          nextToken("error getting label");
690          if (m_st.sval != null) {
691            a.m_label = m_st.sval;
692          }
693          else {
694            System.out.println("error getting label");
695          }
696        }
697        else {
698          System.out.println("error getting label");
699        }
700      }
701      else if (m_st.sval.equalsIgnoreCase("shape")) {
702        nextToken("error getting shape");
703        if (m_st.ttype == '=') {
704          nextToken("error getting shape");
705          if (m_st.sval != null) {
706            a.m_shape = m_st.sval;
707          }
708          else {
709            System.out.println("error getting shape");
710          }
711        }
712        else {
713          System.out.println("error getting shape");
714        }
715      }
716      else if (m_st.sval.equalsIgnoreCase("style")) {
717        nextToken("error getting style");
718        if (m_st.ttype == '=') {
719          nextToken("error getting style");
720          if (m_st.sval != null) {
721            a.m_style = m_st.sval;
722          }
723          else {
724            System.out.println("error getting style");
725          }
726        }
727        else {
728          System.out.println("error getting style");
729        }
730      }
731      else if (m_st.sval.equalsIgnoreCase("data")) {
732        nextToken("error getting data");
733        if (m_st.ttype == '=') {
734          //data has a special data string that can have anything
735          //this is delimited by a single comma on an otherwise empty line
736          alterSyntax();
737          a.m_data = new String("");
738         
739          while (true) {
740            nextToken("error getting data");
741            if (m_st.sval != null && a.m_data 
742                != null && m_st.sval.equals(",")) {
743              break;
744            }
745            else if (m_st.sval != null) {
746              a.m_data = a.m_data.concat(m_st.sval);
747            }
748            else if (m_st.ttype == '\r') {
749              a.m_data = a.m_data.concat("\r");
750            }
751            else if (m_st.ttype == '\n') {
752              a.m_data = a.m_data.concat("\n");
753            }
754            else {
755              System.out.println("error getting data");
756            }
757          }
758          setSyntax();
759        }
760        else {
761          System.out.println("error getting data");
762        }
763      }
764    }
765  }
766
767  //special class for use in creating the tree
768
769  /**
770   * This is an internal class used to keep track of the info for the objects
771   * before they are
772   * actually created.
773   */
774  private class InfoObject {
775    /** The ID string for th object. */
776    public String m_id;
777
778    /** The color name for the object. */
779    public String m_color;
780
781    /** The font color for the object. not in use. */
782    public String m_fontColor;
783
784    /** The fontsize for the object. not in use. */
785    public String m_fontSize;
786
787    /** The label for the object. */
788    public String m_label;
789
790    /** The shape name of for the object. */
791    public String m_shape;
792
793    /** The backstyle name for the object. */
794    public String m_style;
795
796    /** The source ID of the object. */
797    public String m_source;
798
799    /** The target ID of the object. */
800    public String m_target;
801
802    /** The data for this object. */
803    public String m_data;
804
805    /**
806     * This will construct a new InfoObject with the specified ID string.
807     */
808    public InfoObject(String i) {
809      m_id = i;
810      m_color = null;
811      m_fontColor = null;
812      m_fontSize = null;
813      m_label = null;
814      m_shape = null;
815      m_style = null;
816      m_source = null;
817      m_target = null;
818      m_data = null;
819    }
820  }
821}
Note: See TracBrowser for help on using the repository browser.