File: Synopsis/Formatters/HTML/Fragments/HeadingFormatter.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 import ASG
 10from Synopsis.Formatters.HTML.Fragment import Fragment
 11from Synopsis.Formatters.HTML.Tags import *
 12from SourceLinker import SourceLinker
 13from XRefLinker import XRefLinker
 14
 15class HeadingFormatter(Fragment):
 16    """Formats the top of a view - it is passed only the Declaration that the
 17    view is for (a Module or Class)."""
 18
 19    def register(self, formatter):
 20
 21        super(HeadingFormatter, self).register(formatter)
 22        if self.processor.has_view('XRef'):
 23            self.xref = XRefLinker()
 24            self.xref.register(formatter)
 25        else:
 26            self.xref = None
 27        if self.processor.has_view('Source'):
 28            self.source = SourceLinker()
 29            self.source.register(formatter)
 30        else:
 31            self.source = None
 32
 33    def format_name(self, qname):
 34        """Formats a qualified name such that each name component becomes a link
 35        to the respective scope."""
 36
 37        scope, text = type(qname)(), []
 38        for name in qname[:-1]:
 39            scope = scope + (name,)
 40            text.append(self.reference(scope))
 41        text.append(escape(qname[-1]))
 42        return '%s\n'%(qname.sep).join(text) + '\n'
 43
 44    def format_name_in_module(self, qname):
 45        """Formats a reference to each parent scope, starting at the first
 46        non-module scope."""
 47
 48        types = self.processor.ir.asg.types
 49
 50        scope, text = type(qname)(), []
 51        for name in qname[:-1]:
 52            scope += (name,)
 53            if types.has_key(scope):
 54                ns_type = types[scope]
 55                if isinstance(ns_type, ASG.DeclaredTypeId):
 56                    decl = ns_type.declaration
 57                    if isinstance(decl, ASG.Module):
 58                        # Skip modules
 59                        continue
 60            text.append(self.reference(scope))
 61        text.append(escape(qname[-1]))
 62        return '%s\n'%qname.sep.join(text) + '\n'
 63
 64    def format_module_of_name(self, qname):
 65        """Formats a reference to each parent scope and this one."""
 66
 67        types = self.processor.ir.asg.types
 68
 69        scope, text = type(qname)(), []
 70        last_decl = None
 71        for name in qname:
 72            scope += (name,)
 73            if types.has_key(scope):
 74                ns_type = types[scope]
 75                if isinstance(ns_type, ASG.DeclaredTypeId):
 76                    decl = ns_type.declaration
 77                    if isinstance(decl, ASG.Module):
 78                        # Only do modules
 79                        text.append(self.reference(scope))
 80                        last_decl = decl
 81                        continue
 82            break
 83        return last_decl, qname.sep.join(text) + '\n'
 84
 85    def format_module(self, module):
 86        """Formats the module by linking to each parent scope in the name."""
 87
 88        # Module details are only printed at the top of their view
 89        if not module.name:
 90            title = 'Global %s'%module.type.capitalize()
 91        else:
 92            title = '%s %s'%(module.type.capitalize(), self.format_name(module.name))
 93        return element('h1', title)
 94
 95    def format_meta_module(self, module):
 96        """Calls format_module."""
 97
 98        return self.format_module(module)
 99
100    def format_class(self, class_):
101        """Formats the class by linking to each parent scope in the name."""
102
103        # Calculate the module string
104        decl, module = self.format_module_of_name(class_.name)
105        if decl:
106            module = '%s %s'%(decl.type, module)
107            module = div('class-module', module)
108        else:
109            module = ''
110
111        # Calculate class name string
112        type = class_.type
113        name = self.format_name_in_module(class_.name)
114        name = div('class-name', '%s %s'%(type, name))
115
116        # Calculate file-related string
117        file_name = rel(self.processor.output, class_.file.name)
118        # Try the file index view first
119        file_link = self.directory_layout.file_index(class_.file.name)
120        if self.processor.filename_info(file_link):
121            file_ref = href(rel(self.formatter.filename(), file_link), file_name, target='detail')
122        else:
123            # Try source file next
124            file_link = self.directory_layout.file_source(class_.file.name)
125            if self.processor.filename_info(file_link):
126                file_ref = href(rel(self.formatter.filename(), file_link), file_name)
127            else:
128                file_ref = file_name
129
130        links = div('file', 'File: %s'%file_ref)
131        if self.xref: links += ' %s'%div('xref', self.xref.format_class(class_))
132        if self.source: links += ' %s'%div('source', self.source.format_class(class_))
133        info = div('links', links)
134
135        return '%s%s%s'%(module, name, info)
136
137    def format_class_template(self, class_):
138        """Formats the class template by linking to each parent scope in the name."""
139
140        # Calculate the module string
141        decl, module = self.format_module_of_name(class_.name)
142        if decl:
143            module = '%s %s'%(decl.type, module)
144            module = div('class-module', module)
145        else:
146            module = ''
147
148        # Calculate template string
149        templ = class_.template
150        params = templ.parameters
151        params = ', '.join([self.format_parameter(p) for p in params])
152        templ = div('class-template', "template <%s>"%params)
153
154        # Calculate class name string
155        type = class_.type
156        name = self.format_name_in_module(class_.name)
157        name = div('class-name', '%s %s'%(type, name))
158
159        # Calculate file-related string
160        file_name = rel(self.processor.output, class_.file.name)
161        # Try the file index view first
162        file_link = self.directory_layout.file_index(class_.file.name)
163        if self.processor.filename_info(file_link):
164            file_ref = href(rel(self.formatter.filename(), file_link), file_name, target='detail')
165        else:
166            # Try source file next
167            file_link = self.directory_layout.file_source(class_.file.name)
168            if self.processor.filename_info(file_link):
169                file_ref = href(rel(self.formatter.filename(), file_link), file_name)
170            else:
171                file_ref = file_name
172
173        links = div('file', 'File: %s'%file_ref)
174        if self.xref: links += ' %s'%div('xref', self.xref.format_class(class_))
175        if self.source: links += ' %s'%div('source', self.source.format_class(class_))
176        info = div('links', links)
177
178        return '%s%s%s%s'%(module, templ, name, info)
179
180    def format_forward(self, forward):
181        """Formats the forward declaration if it is a template declaration."""
182
183        # Calculate the module string
184        decl, module = self.format_module_of_name(forward.name)
185        if decl:
186            module = '%s %s'%(decl.type, module)
187            module = div('class-module', module)
188        else:
189            module = ''
190
191        # Calculate template string
192        if not forward.template:
193            return ''
194
195        params = forward.template.parameters
196        params = ', '.join([self.format_parameter(p) for p in params])
197        templ = div('class-template', "template <%s>"%params)
198
199        # Calculate class name string
200        type = forward.type
201        name = self.format_name_in_module(forward.name)
202        name = div('class-name', '%s %s'%(type, name))
203
204        # Calculate file-related string
205        file_name = rel(self.processor.output, forward.file.name)
206        # Try the file index view first
207        file_link = self.directory_layout.file_index(forward.file.name)
208        if self.processor.filename_info(file_link):
209            file_ref = href(rel(self.formatter.filename(), file_link), file_name, target='detail')
210        else:
211            # Try source file next
212            file_link = self.directory_layout.file_source(forward.file.name)
213            if self.processor.filename_info(file_link):
214                file_ref = href(rel(self.formatter.filename(), file_link), file_name)
215            else:
216                file_ref = file_name
217
218        links = div('file', 'File: %s'%file_ref)
219        info = div('links', links)
220
221        return '%s%s%s%s'%(module, templ, name, info)
222
223    def format_parameter(self, parameter):
224        """Returns one string for the given parameter"""
225
226        chunks = []
227        # Premodifiers
228        chunks.extend([span("keyword", escape(m)) for m in parameter.premodifier])
229        # Param Type
230        typestr = self.format_type(parameter.type)
231        if typestr: chunks.append(typestr)
232        # Postmodifiers
233        chunks.extend([span("keyword", m) for m in parameter.postmodifier])
234        # Param name
235        if len(parameter.name) != 0:
236            chunks.append(span("variable", parameter.name))
237        # Param value
238        if len(parameter.value) != 0:
239            chunks.append(" = " + span("value", parameter.value))
240        return ' '.join(chunks)
241