Synopsis - Synopsis/Formatters/HTML/Views/InheritanceGraph.py

File: Synopsis/Formatters/HTML/Views/InheritanceGraph.py

      1#
      2# Copyright (C) 2000 Stephen Davies
      3# Copyright (C) 2000 Stefan Seefeld
      4# All rights reserved.
      5# Licensed to the public under the terms of the GNU LGPL (>= 2),
      6# see the file COPYING for details.
      7#
      8
      9from Synopsis.Processor import *
     10from Synopsis import IR, ASG
     11from Synopsis.Formatters.HTML.View import View
     12from Synopsis.Formatters.HTML.Tags import *
     13
     14import os
     15
     16class DeclarationFinder(ASG.Visitor):
     17   def __init__(self, types, verbose):
     18
     19      self.types = types
     20      self.verbose = verbose
     21
     22   def __call__(self, name):
     23      try:
     24         typeobj = self.types[name]
     25      except KeyError:
     26         # Eg: Unknown parent which has been NameMapped
     27         if self.verbose: print "Warning: %s not found in type dict."%(name,)
     28         return None
     29      self.__decl = None
     30      typeobj.accept(self)
     31      #if self.__decl is None:
     32      #    return None
     33      return self.__decl
     34
     35   def visit_buitin_type_id(self, type): return
     36   def visit_unknown_type_id(self, type): return
     37   def visit_declared_type_id(self, type): self.__decl = type.declaration
     38   def visit_modifier_type_id(self, type): type.alias.accept(self)
     39   def visit_array_type_id(self, type): type.alias.accept(self)
     40   def visit_template_id(self, type): self.__decl = type.declaration
     41   def visit_parametrized_type_id(self, type): type.template.accept(self)
     42   def visit_function_type_id(self, type): return
     43
     44def find_common_name(graph):
     45   common_name = list(graph[0])
     46   for decl_name in graph[1:]:
     47      if len(common_name) > len(decl_name):
     48         common_name = common_name[:len(decl_name)]
     49      for i in range(min(len(decl_name), len(common_name))):
     50         if decl_name[i] != common_name[i]:
     51            common_name = common_name[:i]
     52            break
     53   return '::'.join(common_name)
     54
     55class InheritanceGraph(View):
     56
     57   min_size = Parameter(2, 'minimum number of nodes for a graph to be displayed')
     58   min_group_size = Parameter(5, 'how many nodes to put into a group')
     59   direction = Parameter('vertical', 'layout of the graph')
     60
     61   def register(self, frame):
     62
     63      super(InheritanceGraph, self).register(frame)
     64      self.decl_finder = DeclarationFinder(self.processor.ir.asg.types,
     65                                           self.processor.verbose)
     66
     67   def filename(self):
     68
     69      if self.main:
     70         return self.directory_layout.index()
     71      else:
     72         return self.directory_layout.special('InheritanceGraph')
     73
     74   def title(self):
     75
     76      return 'Inheritance Graph'
     77
     78   def root(self):
     79
     80      return self.filename(), self.title()
     81
     82   def consolidate(self, graphs):
     83      """Consolidates small graphs into larger ones"""
     84
     85      # Weed out the small graphs and group by common base name
     86      common = {}
     87      for graph in graphs:
     88         len_graph = len(graph)
     89         if len_graph < self.min_size:
     90            # Ignore the graph
     91            continue
     92         common.setdefault(find_common_name(graph), []).append(graph)
     93      # Consolidate each group
     94      for name, graphs in common.items():
     95         conned = []
     96         pending = []
     97         for graph in graphs:
     98            # Try adding to an already pending graph
     99            for pend in pending:
    100               if len_graph + len(pend) <= self.min_group_size:
    101                  pend.extend(graph)
    102                  graph = None
    103                  if len(pend) == self.min_group_size:
    104                     conned.append(pend)
    105                     pending.remove(pend)
    106                  break
    107            if graph:
    108               if len_graph >= self.min_group_size:
    109                  # Add to final list
    110                  conned.append(graph)
    111               else:
    112                  # Add to pending list
    113                  pending.append(graph)
    114         graphs[:] = conned + pending
    115      return common
    116
    117   def process(self):
    118      """Creates a file with the inheritance graph"""
    119
    120      filename = self.filename()
    121      self.start_file()
    122      self.write_navigation_bar()
    123      self.write(element('h1', "Inheritance Graph"))
    124
    125      from Synopsis.Formatters import Dot
    126      # Create a toc file for Dot to use
    127      toc_file = filename + "-dot.toc"
    128      self.processor.toc.store(toc_file)
    129      graphs = self.processor.class_tree.graphs()
    130      count = 0
    131      # Consolidate the graphs, and sort to make the largest appear first
    132      lensorter = lambda a, b: cmp(len(b),len(a))
    133      common_graphs = self.consolidate(graphs)
    134      names = common_graphs.keys()
    135      names.sort()
    136      for name in names:
    137         graphs = common_graphs[name]
    138         graphs.sort(lensorter)
    139         if name:
    140            self.write('<div class="inheritance-group">')
    141            type_str = ''
    142            types = self.processor.ir.asg.types
    143            type = types.get(name, None)
    144            if isinstance(type, ASG.DeclaredTypeId):
    145               type_str = type.declaration.type + ' '
    146            self.write('Graphs in '+type_str+name+':<br/>')
    147         for graph in graphs:
    148            if self.processor.verbose: print "Creating graph #%s - %s classes"%(count,len(graph))
    149            # Find declarations
    150            declarations = map(self.decl_finder, graph)
    151            declarations = filter(lambda x: x is not None, declarations)
    152            #output = os.path.join(self.processor.output, 'InheritanceGraph', str(count))
    153            output = os.path.join(self.processor.output,
    154                                  os.path.splitext(self.filename())[0]) + '-%s'%count
    155            dot = Dot.Formatter(bgcolor=self.processor.graph_color)
    156            ir = IR.IR(files={}, asg=ASG.ASG(declarations, self.processor.ir.asg.types))
    157            try:
    158               dot.process(ir,
    159                           output=output,
    160                           format='html',
    161                           toc_in=[toc_file],
    162                           base_url=self.filename(),
    163                           title='Synopsis %s'%count,
    164                           layout=self.direction)
    165               dot_file = open(output + '.html', 'r')
    166               self.write(dot_file.read())
    167               dot_file.close()
    168               os.remove(output + ".html")
    169            except InvalidCommand, e:
    170               print 'Warning : %s'%str(e)
    171            count = count + 1
    172         if name:
    173            self.write('</div>')
    174
    175      os.remove(toc_file)
    176
    177      self.end_file()
    178

Generated on Thu Apr 16 16:27:14 2009 by
synopsis (version devel)